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:
parent
30151b7694
commit
4dfe25cdd8
@ -24,7 +24,7 @@
|
|||||||
"release": "release-it --non-interactive",
|
"release": "release-it --non-interactive",
|
||||||
"changelog": "auto-changelog -p",
|
"changelog": "auto-changelog -p",
|
||||||
"prepublishOnly": "npm run build",
|
"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: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": "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",
|
"test:unit:cover": "nyc --report-dir coverage/unit npm run test:unit",
|
||||||
|
@ -785,7 +785,7 @@ export class Pool {
|
|||||||
minAmountOutFormatted.toString(),
|
minAmountOutFormatted.toString(),
|
||||||
maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256
|
maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256
|
||||||
)
|
)
|
||||||
console.log(minAmountOutFormatted, 'minamoutnoutformatted')
|
//console.log(minAmountOutFormatted, 'minamoutnoutformatted')
|
||||||
try {
|
try {
|
||||||
result = await pool.methods
|
result = await pool.methods
|
||||||
.swapExactAmountIn(
|
.swapExactAmountIn(
|
||||||
|
490
src/pools/ssContracts/SideStaking.ts
Normal file
490
src/pools/ssContracts/SideStaking.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
1
src/pools/ssContracts/index.ts
Normal file
1
src/pools/ssContracts/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './SideStaking'
|
@ -123,6 +123,8 @@ describe('Pool unit test', () => {
|
|||||||
await usdcContract.methods.decimals().call(),
|
await usdcContract.methods.decimals().call(),
|
||||||
'USDC DECIMALS IN THIS TEST'
|
'USDC DECIMALS IN THIS TEST'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await pool.amountToUnits(contracts.usdcAddress, '20')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Test a pool with DAI (18 Decimals)', () => {
|
describe('Test a pool with DAI (18 Decimals)', () => {
|
||||||
|
520
test/unit/pools/ssContracts/SideStaking.test.ts
Normal file
520
test/unit/pools/ssContracts/SideStaking.test.ts
Normal 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)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user