1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00

add SideStaking class, add initial unit test setup

This commit is contained in:
lacoop6tu 2021-11-01 17:13:02 -05:00
parent 30151b7694
commit 4dfe25cdd8
6 changed files with 1015 additions and 2 deletions

View File

@ -24,7 +24,7 @@
"release": "release-it --non-interactive",
"changelog": "auto-changelog -p",
"prepublishOnly": "npm run build",
"test:pool": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/pools/balancer/Pool.test.ts'",
"test:ss": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/pools/ssContracts/SideStaking.test.ts'",
"test:router": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/pools/Router.test.ts'",
"test:unit": "mocha --config=test/unit/.mocharc.json --node-env=test --exit 'test/unit/**/*.test.ts'",
"test:unit:cover": "nyc --report-dir coverage/unit npm run test:unit",

View File

@ -785,7 +785,7 @@ export class Pool {
minAmountOutFormatted.toString(),
maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256
)
console.log(minAmountOutFormatted, 'minamoutnoutformatted')
//console.log(minAmountOutFormatted, 'minamoutnoutformatted')
try {
result = await pool.methods
.swapExactAmountIn(

View File

@ -0,0 +1,490 @@
import Web3 from 'web3'
import { AbiItem } from 'web3-utils/types'
import { TransactionReceipt } from 'web3-core'
import { Contract } from 'web3-eth-contract'
import { Logger, getFairGasPrice } from '../../utils'
import BigNumber from 'bignumber.js'
import SideStakingTemplate from '@oceanprotocol/contracts/artifacts/contracts/pools/ssContracts/SideStaking.sol/SideStaking.json'
import defaultPool from '@oceanprotocol/contracts/artifacts/contracts/pools/FactoryRouter.sol/FactoryRouter.json'
import defaultERC20ABI from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json'
import Decimal from 'decimal.js'
const MaxUint256 =
'115792089237316195423570985008687907853269984665640564039457584007913129639934'
/**
* Provides an interface to Ocean friendly fork from Balancer BPool
*/
// TODO: Add decimals handling
export class SideStaking {
public ssABI: AbiItem | AbiItem[]
public web3: Web3
public GASLIMIT_DEFAULT = 1000000
private logger: Logger
constructor(web3: Web3, logger: Logger, ssABI: AbiItem | AbiItem[] = null) {
if (ssABI) this.ssABI = ssABI
else this.ssABI = SideStakingTemplate.abi as AbiItem[]
this.web3 = web3
this.logger = logger
}
async amountToUnits(token: string, amount: string): Promise<string> {
let decimals = 18
const tokenContract = new this.web3.eth.Contract(
defaultERC20ABI.abi as AbiItem[],
token
)
try {
decimals = await tokenContract.methods.decimals().call()
} catch (e) {
this.logger.error('ERROR: FAILED TO CALL DECIMALS(), USING 18')
}
const amountFormatted = new BigNumber(parseInt(amount) * 10 ** decimals)
return amountFormatted.toString()
}
async unitsToAmount(token: string, amount: string): Promise<string> {
let decimals = 18
const tokenContract = new this.web3.eth.Contract(
defaultERC20ABI.abi as AbiItem[],
token
)
try {
decimals = await tokenContract.methods.decimals().call()
} catch (e) {
this.logger.error('ERROR: FAILED TO CALL DECIMALS(), USING 18')
}
const amountFormatted = new BigNumber(parseInt(amount) / 10 ** decimals)
return amountFormatted.toString()
}
/**
* Estimate gas cost for collectMarketFee
* @param {String} account
* @param {String} tokenAddress
* @param {String} spender
* @param {String} amount
* @param {String} force
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estApprove(
account: string,
tokenAddress: string,
spender: string,
amount: string,
contractInstance?: Contract
): Promise<number> {
const tokenContract =
contractInstance ||
new this.web3.eth.Contract(defaultERC20ABI.abi as AbiItem[], tokenAddress)
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await tokenContract.methods
.approve(spender, amount)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Get Alloance for both DataToken and Ocean
* @param {String } tokenAdress
* @param {String} owner
* @param {String} spender
*/
public async allowance(
tokenAddress: string,
owner: string,
spender: string
): Promise<string> {
const tokenAbi = defaultERC20ABI.abi as AbiItem[]
const datatoken = new this.web3.eth.Contract(tokenAbi, tokenAddress)
const trxReceipt = await datatoken.methods.allowance(owner, spender).call()
return await this.unitsToAmount(tokenAddress, trxReceipt)
}
/**
* Approve spender to spent amount tokens
* @param {String} account
* @param {String} tokenAddress
* @param {String} spender
* @param {String} amount (always expressed as wei)
* @param {String} force if true, will overwrite any previous allowence. Else, will check if allowence is enough and will not send a transaction if it's not needed
*/
async approve(
account: string,
tokenAddress: string,
spender: string,
amount: string,
force = false
): Promise<TransactionReceipt | string> {
const minABI = [
{
constant: false,
inputs: [
{
name: '_spender',
type: 'address'
},
{
name: '_value',
type: 'uint256'
}
],
name: 'approve',
outputs: [
{
name: '',
type: 'bool'
}
],
payable: false,
stateMutability: 'nonpayable',
type: 'function'
}
] as AbiItem[]
const token = new this.web3.eth.Contract(minABI, tokenAddress)
if (!force) {
const currentAllowence = await this.allowance(tokenAddress, account, spender)
if (new Decimal(currentAllowence).greaterThanOrEqualTo(amount)) {
return currentAllowence
}
}
let result = null
const amountFormatted = await this.amountToUnits(tokenAddress, amount)
const estGas = await this.estApprove(account, tokenAddress, spender, amountFormatted)
try {
result = await token.methods
.approve(spender, new BigNumber(await this.amountToUnits(tokenAddress, amount)))
.send({
from: account,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
} catch (e) {
this.logger.error(`ERRPR: Failed to approve spender to spend tokens : ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @return {String}
*/
async getDataTokenCirculatingSupply(
ssAddress: string,
datatokenAddress: string
): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods
.getDataTokenCirculatingSupply(datatokenAddress)
.call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @return {String}
*/
async getPublisherAddress(
ssAddress: string,
datatokenAddress: string
): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getPublisherAddress(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getBasetoken(ssAddress: string, datatokenAddress: string): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getBaseToken(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getPoolAddress(ssAddress: string, datatokenAddress: string): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getPoolAddress(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getBasetokenBalance(
ssAddress: string,
datatokenAddress: string
): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getBasetokenBalance(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getDatatokenBalance(
ssAddress: string,
datatokenAddress: string
): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getDatatokenBalance(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getvestingEndBlock(ssAddress: string, datatokenAddress: string): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getvestingEndBlock(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getvestingAmount(ssAddress: string, datatokenAddress: string): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getvestingAmount(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getvestingLastBlock(
ssAddress: string,
datatokenAddress: string
): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getvestingLastBlock(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {String}
*/
async getvestingAmountSoFar(
ssAddress: string,
datatokenAddress: string
): Promise<string> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods.getvestingAmountSoFar(datatokenAddress).call()
} catch (e) {
this.logger.error(`ERROR: Failed to get: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @param {String} amount amount of DTs we want to Side Staking to stake
* @return {String}
*/
async canStake(
ssAddress: string,
datatokenAddress: string,
amount: string
): Promise<boolean> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods
.canStake(
datatokenAddress,
await this.getBasetoken(ssAddress, datatokenAddress),
this.amountToUnits(datatokenAddress, amount)
)
.call()
} catch (e) {
this.logger.error(`ERROR: Failed to get if can stake DT: ${e.message}`)
}
return result
}
/**
* Get
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @param {String} amount amount of LPT we want to Side Staking to unstake
* @return {String}
*/
async canUnStake(
ssAddress: string,
datatokenAddress: string,
amount: string
): Promise<boolean> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
try {
result = await sideStaking.methods
.canUnStake(
datatokenAddress,
await this.getBasetoken(ssAddress, datatokenAddress),
this.amountToUnits(
await this.getPoolAddress(ssAddress, datatokenAddress),
amount
)
)
.call()
} catch (e) {
this.logger.error(`ERROR: Failed to get if can stake DT: ${e.message}`)
}
return result
}
/**
* Estimate gas cost for collectMarketFee
* @param {String} account
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estGetVesting(
account: string,
ssAddress: string,
datatokenAddress: string,
contractInstance?: Contract
): Promise<number> {
const sideStaking =
contractInstance || new this.web3.eth.Contract(this.ssABI as AbiItem[], ssAddress)
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await sideStaking.methods
.getVesting(datatokenAddress)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
*
* @param {String} account
* @param {String} ssAddress side staking contract address
* @param {String} datatokenAddress datatokenAddress
* @return {TransactionReceipt}
*/
async getVesting(
account: string,
ssAddress: string,
datatokenAddress: string
): Promise<TransactionReceipt> {
const sideStaking = new this.web3.eth.Contract(this.ssABI, ssAddress)
let result = null
const estGas = await this.estGetVesting(
account,
ssAddress,
datatokenAddress,
sideStaking
)
try {
result = await sideStaking.methods.getVesting(datatokenAddress).send({
from: account,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
} catch (e) {
this.logger.error('ERROR: Failed to join swap pool amount out')
}
return result
}
}

View File

@ -0,0 +1 @@
export * from './SideStaking'

View File

@ -123,6 +123,8 @@ describe('Pool unit test', () => {
await usdcContract.methods.decimals().call(),
'USDC DECIMALS IN THIS TEST'
)
await pool.amountToUnits(contracts.usdcAddress, '20')
})
describe('Test a pool with DAI (18 Decimals)', () => {

View File

@ -0,0 +1,520 @@
import { assert, expect } from 'chai'
import { AbiItem } from 'web3-utils/types'
import { TestContractHandler } from '../../../TestContractHandler'
import { Contract } from 'web3-eth-contract'
import Web3 from 'web3'
import BigNumber from 'bignumber.js'
import ERC721Factory from '@oceanprotocol/contracts/artifacts/contracts/ERC721Factory.sol/ERC721Factory.json'
import ERC721Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC721Template.sol/ERC721Template.json'
import SSContract from '@oceanprotocol/contracts/artifacts/contracts/pools/ssContracts/SideStaking.sol/SideStaking.json'
import FactoryRouter from '@oceanprotocol/contracts/artifacts/contracts/pools/FactoryRouter.sol/FactoryRouter.json'
import ERC20Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json'
import Dispenser from '@oceanprotocol/contracts/artifacts/contracts/pools/dispenser/Dispenser.sol/Dispenser.json'
import FixedRate from '@oceanprotocol/contracts/artifacts/contracts/pools/fixedRate/FixedRateExchange.sol/FixedRateExchange.json'
import MockERC20 from '@oceanprotocol/contracts/artifacts/contracts/utils/mock/MockERC20Decimals.sol/MockERC20Decimals.json'
import PoolTemplate from '@oceanprotocol/contracts/artifacts/contracts/pools/balancer/BPool.sol/BPool.json'
import OPFCollector from '@oceanprotocol/contracts/artifacts/contracts/communityFee/OPFCommunityFeeCollector.sol/OPFCommunityFeeCollector.json'
import { LoggerInstance } from '../../../../src/utils'
import { NFTFactory } from '../../../../src/factories/NFTFactory'
import { Pool } from '../../../../src/pools/balancer/Pool'
import { SideStaking } from '../../../../src/pools/ssContracts/SideStaking'
const { keccak256 } = require('@ethersproject/keccak256')
const web3 = new Web3('http://127.0.0.1:8545')
const communityCollector = '0xeE9300b7961e0a01d9f0adb863C7A227A07AaD75'
describe('SideStaking unit test', () => {
let factoryOwner: string
let nftOwner: string
let user1: string
let user2: string
let user3: string
let contracts: TestContractHandler
let pool: Pool
let sideStaking: SideStaking
let dtAddress: string
let dtAddress2: string
let poolAddress: string
let erc20Token: string
let erc20Contract: Contract
let daiContract: Contract
let usdcContract: Contract
it('should deploy contracts', async () => {
contracts = new TestContractHandler(
web3,
ERC721Template.abi as AbiItem[],
ERC20Template.abi as AbiItem[],
PoolTemplate.abi as AbiItem[],
ERC721Factory.abi as AbiItem[],
FactoryRouter.abi as AbiItem[],
SSContract.abi as AbiItem[],
FixedRate.abi as AbiItem[],
Dispenser.abi as AbiItem[],
OPFCollector.abi as AbiItem[],
ERC721Template.bytecode,
ERC20Template.bytecode,
PoolTemplate.bytecode,
ERC721Factory.bytecode,
FactoryRouter.bytecode,
SSContract.bytecode,
FixedRate.bytecode,
Dispenser.bytecode,
OPFCollector.bytecode
)
await contracts.getAccounts()
factoryOwner = contracts.accounts[0]
nftOwner = contracts.accounts[1]
user1 = contracts.accounts[2]
user2 = contracts.accounts[3]
user3 = contracts.accounts[4]
await contracts.deployContracts(factoryOwner, FactoryRouter.abi as AbiItem[])
// initialize Pool instance
pool = new Pool(web3, LoggerInstance, PoolTemplate.abi as AbiItem[])
assert(pool != null)
//
sideStaking = new SideStaking(web3, LoggerInstance, SSContract.abi as AbiItem[])
assert(sideStaking != null)
daiContract = new web3.eth.Contract(
contracts.MockERC20.options.jsonInterface,
contracts.daiAddress
)
usdcContract = new web3.eth.Contract(
contracts.MockERC20.options.jsonInterface,
contracts.usdcAddress
)
await pool.approve(
contracts.accounts[0],
contracts.daiAddress,
contracts.factory721Address,
'2000'
)
await pool.approve(
contracts.accounts[0],
contracts.usdcAddress,
contracts.factory721Address,
'10000'
)
expect(
await pool.allowance(
contracts.daiAddress,
contracts.accounts[0],
contracts.factory721Address
)
).to.equal('2000')
expect(
await pool.allowance(
contracts.usdcAddress,
contracts.accounts[0],
contracts.factory721Address
)
).to.equal('10000')
expect(await daiContract.methods.balanceOf(contracts.accounts[0]).call()).to.equal(
web3.utils.toWei('100000')
)
console.log(
await usdcContract.methods.decimals().call(),
'USDC DECIMALS IN THIS TEST'
)
await pool.amountToUnits(contracts.usdcAddress, '20')
})
describe('Test a pool with DAI (18 Decimals)', () => {
it('#create a pool', async () => {
// CREATE A POOL
// we prepare transaction parameters objects
const nftData = {
name: '72120Bundle',
symbol: '72Bundle',
templateIndex: 1,
baseURI: 'https://oceanprotocol.com/nft/'
}
const ercData = {
templateIndex: 1,
strings: ['ERC20B1', 'ERC20DT1Symbol'],
addresses: [
contracts.accounts[0],
user3,
contracts.accounts[0],
'0x0000000000000000000000000000000000000000'
],
uints: [web3.utils.toWei('1000000'), 0],
bytess: []
}
const basetokenInitialLiq = await pool.amountToUnits(contracts.daiAddress, '2000')
const poolData = {
addresses: [
contracts.sideStakingAddress,
contracts.daiAddress,
contracts.factory721Address,
contracts.accounts[0],
contracts.accounts[0],
contracts.poolTemplateAddress
],
ssParams: [
web3.utils.toWei('1'), // rate
18, // basetokenDecimals
web3.utils.toWei('10000'),
2500000, // vested blocks
web3.utils.toWei('2000') // baseToken initial pool liquidity
],
swapFees: [
1e15, //
1e15
]
}
const nftFactory = new NFTFactory(contracts.factory721Address, web3, LoggerInstance)
const txReceipt = await nftFactory.createNftErcWithPool(
contracts.accounts[0],
nftData,
ercData,
poolData
)
erc20Token = txReceipt.events.TokenCreated.returnValues.newTokenAddress
poolAddress = txReceipt.events.NewPool.returnValues.poolAddress
erc20Contract = new web3.eth.Contract(ERC20Template.abi as AbiItem[], erc20Token)
// user2 has no dt1
expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0')
})
it('#swapExactAmountIn - should swap', async () => {
await daiContract.methods
.transfer(user2, web3.utils.toWei('1000'))
.send({ from: contracts.accounts[0] })
expect(await daiContract.methods.balanceOf(user2).call()).to.equal(
web3.utils.toWei('1000')
)
expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0')
await pool.approve(user2, contracts.daiAddress, poolAddress, '10')
const tx = await pool.swapExactAmountIn(
user2,
poolAddress,
contracts.daiAddress,
'10',
erc20Token,
'1'
)
expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal(
tx.events.LOG_SWAP.returnValues.tokenAmountOut
)
})
it('#swapExactAmountOut - should swap', async () => {
await pool.approve(user2, contracts.daiAddress, poolAddress, '100')
expect(await daiContract.methods.balanceOf(user2).call()).to.equal(
web3.utils.toWei('990')
)
const tx = await pool.swapExactAmountOut(
user2,
poolAddress,
contracts.daiAddress,
'100',
erc20Token,
'50'
)
assert(tx != null)
})
it('#joinswapExternAmountIn- user2 should add liquidity, receiving LP tokens', async () => {
const daiAmountIn = '100'
const minBPTOut = '0.1'
await pool.approve(user2, contracts.daiAddress, poolAddress, '100', true)
expect(await pool.allowance(contracts.daiAddress, user2, poolAddress)).to.equal(
'100'
)
const tx = await pool.joinswapExternAmountIn(
user2,
poolAddress,
contracts.daiAddress,
daiAmountIn,
minBPTOut
)
assert(tx != null)
expect(tx.events.LOG_JOIN[0].event === 'LOG_JOIN')
expect(tx.events.LOG_BPT.event === 'LOG_BPT')
// 2 JOIN EVENTS BECAUSE SIDE STAKING ALSO STAKED DTs, TODO: we should add to whom has been sent in the LOG_BPT event
expect(tx.events.LOG_JOIN[0].returnValues.bptAmount).to.equal(
tx.events.LOG_JOIN[1].returnValues.bptAmount
)
})
it('#joinswapPoolAmountOut- user2 should add liquidity, receiving LP tokens', async () => {
const BPTAmountOut = '0.1'
const maxDAIIn = '100'
await pool.approve(user2, contracts.daiAddress, poolAddress, '100')
const tx = await pool.joinswapPoolAmountOut(
user2,
poolAddress,
contracts.daiAddress,
BPTAmountOut,
maxDAIIn
)
assert(tx != null)
expect(tx.events.LOG_JOIN[0].event === 'LOG_JOIN')
expect(tx.events.LOG_BPT.event === 'LOG_BPT')
// 2 JOIN EVENTS BECAUSE SIDE STAKING ALSO STAKED DTs, TODO: we should add to whom has been sent in the LOG_BPT event
expect(tx.events.LOG_JOIN[0].returnValues.bptAmount).to.equal(
tx.events.LOG_JOIN[1].returnValues.bptAmount
)
})
it('#exitswapPoolAmountIn- user2 exit the pool receiving only DAI', async () => {
const BPTAmountIn = '0.5'
const minDAIOut = '0.5'
const tx = await pool.exitswapPoolAmountIn(
user2,
poolAddress,
contracts.daiAddress,
BPTAmountIn,
minDAIOut
)
assert(tx != null)
expect(tx.events.LOG_EXIT[0].returnValues.tokenOut).to.equal(contracts.daiAddress)
// DTs were also unstaked in the same transaction (went to the staking contract)
expect(tx.events.LOG_EXIT[1].returnValues.tokenOut).to.equal(erc20Token)
})
it('#exitswapExternAmountOut- user2 exit the pool receiving only DAI', async () => {
const maxBTPIn = '0.5'
const exactDAIOut = '1'
const tx = await pool.exitswapPoolAmountIn(
user2,
poolAddress,
contracts.daiAddress,
maxBTPIn,
exactDAIOut
)
assert(tx != null)
expect(tx.events.LOG_EXIT[0].returnValues.tokenOut).to.equal(contracts.daiAddress)
// DTs were also unstaked in the same transaction (went to the staking contract)
expect(tx.events.LOG_EXIT[1].returnValues.tokenOut).to.equal(erc20Token)
})
})
describe('Test a pool with USDC (6 Decimals)', () => {
it('#create a pool', async () => {
// CREATE A POOL
// we prepare transaction parameters objects
const nftData = {
name: '72120Bundle',
symbol: '72Bundle',
templateIndex: 1,
baseURI: 'https://oceanprotocol.com/nft/'
}
const ercData = {
templateIndex: 1,
strings: ['ERC20B1', 'ERC20DT1Symbol'],
addresses: [
contracts.accounts[0],
user3,
contracts.accounts[0],
'0x0000000000000000000000000000000000000000'
],
uints: [web3.utils.toWei('1000000'), 0],
bytess: []
}
const basetokenInitialLiq = Number(
await pool.amountToUnits(contracts.usdcAddress, '2000')
)
const poolData = {
addresses: [
contracts.sideStakingAddress,
contracts.usdcAddress,
contracts.factory721Address,
contracts.accounts[0],
contracts.accounts[0],
contracts.poolTemplateAddress
],
ssParams: [
web3.utils.toWei('1'), // rate
await usdcContract.methods.decimals().call(), // basetokenDecimals
web3.utils.toWei('10000'),
2500000, // vested blocks
basetokenInitialLiq // baseToken initial pool liquidity
],
swapFees: [
1e15, //
1e15
]
}
const nftFactory = new NFTFactory(contracts.factory721Address, web3, LoggerInstance)
const txReceipt = await nftFactory.createNftErcWithPool(
contracts.accounts[0],
nftData,
ercData,
poolData
)
erc20Token = txReceipt.events.TokenCreated.returnValues.newTokenAddress
poolAddress = txReceipt.events.NewPool.returnValues.poolAddress
erc20Contract = new web3.eth.Contract(ERC20Template.abi as AbiItem[], erc20Token)
// user2 has no dt1
expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0')
})
it('#swapExactAmountIn - should swap', async () => {
const transferAmount = await pool.amountToUnits(contracts.usdcAddress, '1000') // 1000 USDC
await usdcContract.methods
.transfer(user2, transferAmount)
.send({ from: contracts.accounts[0] })
expect(await usdcContract.methods.balanceOf(user2).call()).to.equal(
transferAmount.toString()
)
expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal('0')
await pool.approve(user2, contracts.usdcAddress, poolAddress, '10')
const tx = await pool.swapExactAmountIn(
user2,
poolAddress,
contracts.usdcAddress,
'10',
erc20Token,
'1'
)
expect(await erc20Contract.methods.balanceOf(user2).call()).to.equal(
tx.events.LOG_SWAP.returnValues.tokenAmountOut
)
})
it('#swapExactAmountOut - should swap', async () => {
expect(await usdcContract.methods.balanceOf(user2).call()).to.equal(
(await pool.amountToUnits(contracts.usdcAddress, '990')).toString()
)
await pool.approve(user2, contracts.usdcAddress, poolAddress, '100')
const tx = await pool.swapExactAmountOut(
user2,
poolAddress,
contracts.usdcAddress,
'100',
erc20Token,
'50'
)
assert(tx != null)
// console.log(tx.events)
})
it('#joinswapExternAmountIn- user2 should add liquidity, receiving LP tokens', async () => {
const usdcAmountIn = '100'
const minBPTOut = '0.1'
await pool.approve(user2, contracts.usdcAddress, poolAddress, '100', true)
const tx = await pool.joinswapExternAmountIn(
user2,
poolAddress,
contracts.usdcAddress,
usdcAmountIn,
minBPTOut
)
assert(tx != null)
expect(tx.events.LOG_JOIN[0].event === 'LOG_JOIN')
expect(tx.events.LOG_BPT.event === 'LOG_BPT')
// 2 JOIN EVENTS BECAUSE SIDE STAKING ALSO STAKED DTs, TODO: we should add to whom has been sent in the LOG_BPT event
expect(tx.events.LOG_JOIN[0].returnValues.bptAmount).to.equal(
tx.events.LOG_JOIN[1].returnValues.bptAmount
)
})
it('#joinswapPoolAmountOut- user2 should add liquidity, receiving LP tokens', async () => {
const BPTAmountOut = '0.1'
const maxUSDCIn = '100'
await pool.approve(user2, contracts.usdcAddress, poolAddress, '100')
const tx = await pool.joinswapPoolAmountOut(
user2,
poolAddress,
contracts.usdcAddress,
BPTAmountOut,
maxUSDCIn
)
assert(tx != null)
expect(tx.events.LOG_JOIN[0].event === 'LOG_JOIN')
expect(tx.events.LOG_BPT.event === 'LOG_BPT')
// 2 JOIN EVENTS BECAUSE SIDE STAKING ALSO STAKED DTs, TODO: we should add to whom has been sent in the LOG_BPT event
expect(tx.events.LOG_JOIN[0].returnValues.bptAmount).to.equal(
tx.events.LOG_JOIN[1].returnValues.bptAmount
)
})
it('#exitswapPoolAmountIn- user2 exit the pool receiving only USDC', async () => {
const BPTAmountIn = '0.5'
const minUSDCOut = '0.5'
const tx = await pool.exitswapPoolAmountIn(
user2,
poolAddress,
contracts.usdcAddress,
BPTAmountIn,
minUSDCOut
)
assert(tx != null)
expect(tx.events.LOG_EXIT[0].returnValues.tokenOut).to.equal(contracts.usdcAddress)
// DTs were also unstaked in the same transaction (went to the staking contract)
expect(tx.events.LOG_EXIT[1].returnValues.tokenOut).to.equal(erc20Token)
})
it('#exitswapExternAmountOut- user2 exit the pool receiving only USDC', async () => {
const maxBTPIn = '0.5'
const exactUSDCOut = '1'
const tx = await pool.exitswapPoolAmountIn(
user2,
poolAddress,
contracts.usdcAddress,
maxBTPIn,
exactUSDCOut
)
assert(tx != null)
expect(tx.events.LOG_EXIT[0].returnValues.tokenOut).to.equal(contracts.usdcAddress)
// DTs were also unstaked in the same transaction (went to the staking contract)
expect(tx.events.LOG_EXIT[1].returnValues.tokenOut).to.equal(erc20Token)
})
})
})