mirror of
https://github.com/oceanprotocol/ocean.js.git
synced 2024-11-26 20:39:05 +01:00
Merge pull request #138 from oceanprotocol/feature/balancer
Feature/balancer
This commit is contained in:
commit
9b0bee708e
333
src/balancer/OceanPool.ts
Normal file
333
src/balancer/OceanPool.ts
Normal file
@ -0,0 +1,333 @@
|
||||
import { Pool } from './balancerlib'
|
||||
|
||||
export class OceanPool extends Pool {
|
||||
/** Ocean related functions */
|
||||
public oceanAddress: string = null
|
||||
public dtAddress: string = null
|
||||
|
||||
constructor(
|
||||
web3: any,
|
||||
FactoryABI: any = null,
|
||||
PoolABI: any = null,
|
||||
factoryAddress: string = null,
|
||||
oceanAddress: string = null,
|
||||
gaslimit?: number
|
||||
) {
|
||||
super(web3, FactoryABI, PoolABI, factoryAddress, gaslimit)
|
||||
if (oceanAddress) {
|
||||
this.oceanAddress = oceanAddress
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create DataToken pool
|
||||
@param {String} account
|
||||
* @param {String} token Data Token Address
|
||||
* @param {String} amount Data Token Amount
|
||||
* @param {String} weight Data Token Weight
|
||||
* @return {any}
|
||||
*/
|
||||
public async createDTPool(
|
||||
account: string,
|
||||
token: string,
|
||||
amount: string,
|
||||
weight: string,
|
||||
fee: string,
|
||||
finalize: boolean = true
|
||||
): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
if (parseFloat(weight) > 9 || parseFloat(weight) < 1) {
|
||||
console.error('Weight out of bounds (min 1, max9)')
|
||||
return null
|
||||
}
|
||||
const address = await super.createPool(account)
|
||||
const oceanWeight = 10 - parseFloat(weight)
|
||||
const oceanAmount = (parseFloat(amount) * oceanWeight) / parseFloat(weight)
|
||||
const tokens = [
|
||||
{
|
||||
address: token,
|
||||
amount: String(amount),
|
||||
weight: String(weight)
|
||||
},
|
||||
{
|
||||
address: this.oceanAddress,
|
||||
amount: String(oceanAmount),
|
||||
weight: String(oceanWeight)
|
||||
}
|
||||
]
|
||||
this.dtAddress = token
|
||||
await super.addToPool(account, address, tokens)
|
||||
await super.setSwapFee(account, address, fee)
|
||||
if (finalize) await super.finalize(account, address)
|
||||
return address
|
||||
}
|
||||
|
||||
/* Get DataToken address of token in this pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {string}
|
||||
*/
|
||||
public async getDTAddress(account: string, poolAddress: string): Promise<string> {
|
||||
this.dtAddress = null
|
||||
const tokens = await this.getCurrentTokens(account, poolAddress)
|
||||
let token
|
||||
for (token of tokens) {
|
||||
if (token !== this.oceanAddress) this.dtAddress = token
|
||||
}
|
||||
return this.dtAddress
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Ocean Token balance of a pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {any}
|
||||
*/
|
||||
public async getOceanReserve(account: string, poolAddress: string): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
return super.getReserve(account, poolAddress, this.oceanAddress)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Data Token balance of a pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {any}
|
||||
*/
|
||||
public async getDTReserve(account: string, poolAddress: string): Promise<any> {
|
||||
await this.getDTAddress(account, poolAddress)
|
||||
return super.getReserve(account, poolAddress, this.dtAddress)
|
||||
}
|
||||
|
||||
/**
|
||||
* Buy Data Token from a pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} amount Data Token Amount
|
||||
* @param {String} oceanAmount Ocean Token Amount payed
|
||||
* @param {String} maxPrice Maximum Price to pay
|
||||
* @return {any}
|
||||
*/
|
||||
public async buyDT(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
amount: string,
|
||||
oceanAmount: string,
|
||||
maxPrice: string
|
||||
): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
await this.getDTAddress(account, poolAddress)
|
||||
|
||||
// TODO - check balances first
|
||||
await super.approve(
|
||||
account,
|
||||
this.oceanAddress,
|
||||
poolAddress,
|
||||
this.web3.utils.toWei(oceanAmount)
|
||||
)
|
||||
|
||||
return this.swapExactAmountOut(
|
||||
account,
|
||||
poolAddress,
|
||||
this.oceanAddress,
|
||||
oceanAmount,
|
||||
this.dtAddress,
|
||||
amount,
|
||||
maxPrice
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sell Data Token
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} amount Data Token Amount
|
||||
* @param {String} oceanAmount Ocean Token Amount expected
|
||||
* @param {String} maxPrice Minimum Price to sell
|
||||
* @return {any}
|
||||
*/
|
||||
public async sellDT(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
amount: string,
|
||||
oceanAmount: string,
|
||||
minPrice: string
|
||||
): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
await this.getDTAddress(account, poolAddress)
|
||||
return this.swapExactAmountOut(
|
||||
account,
|
||||
poolAddress,
|
||||
this.dtAddress,
|
||||
amount,
|
||||
this.oceanAddress,
|
||||
oceanAmount,
|
||||
minPrice
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Data Token amount to pool liquidity
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} amount Data Token Amount
|
||||
* @return {any}
|
||||
*/
|
||||
public async addDTLiquidity(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
amount: string
|
||||
): Promise<any> {
|
||||
await this.getDTAddress(account, poolAddress)
|
||||
await super.approve(
|
||||
account,
|
||||
this.dtAddress,
|
||||
poolAddress,
|
||||
this.web3.utils.toWei(amount)
|
||||
)
|
||||
const result = await super.joinswapExternAmountIn(
|
||||
account,
|
||||
poolAddress,
|
||||
this.dtAddress,
|
||||
amount,
|
||||
'0'
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Data Token amount from pool liquidity
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} amount pool Liquidity Amount
|
||||
* @return {any}
|
||||
*/
|
||||
public async removeDTLiquidity(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
amount: string,
|
||||
maximumPoolShares: string
|
||||
): Promise<any> {
|
||||
await this.getDTAddress(account, poolAddress)
|
||||
// TODO Check balance of PoolShares before doing exit
|
||||
return this.exitswapExternAmountOut(
|
||||
account,
|
||||
poolAddress,
|
||||
this.dtAddress,
|
||||
amount,
|
||||
maximumPoolShares
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Ocean Token amount to pool liquidity
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} amount Data Token Amount
|
||||
* @return {any}
|
||||
*/
|
||||
public async addOceanLiquidity(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
amount: string
|
||||
): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
await super.approve(
|
||||
account,
|
||||
this.oceanAddress,
|
||||
poolAddress,
|
||||
this.web3.utils.toWei(amount)
|
||||
)
|
||||
const result = await super.joinswapExternAmountIn(
|
||||
account,
|
||||
poolAddress,
|
||||
this.oceanAddress,
|
||||
amount,
|
||||
'0'
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Ocean Token amount from pool liquidity
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} amount pool Liquidity Amount
|
||||
* @return {any}
|
||||
*/
|
||||
public removeOceanLiquidity(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
amount: string,
|
||||
maximumPoolShares: string
|
||||
): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
// TODO Check balance of PoolShares before doing exit
|
||||
return super.exitswapExternAmountOut(
|
||||
account,
|
||||
poolAddress,
|
||||
this.oceanAddress,
|
||||
amount,
|
||||
maximumPoolShares
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Data Token Price from pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {any}
|
||||
*/
|
||||
public async getDTPrice(account: string, poolAddress: string): Promise<any> {
|
||||
if (this.oceanAddress == null) {
|
||||
console.error('oceanAddress is not defined')
|
||||
return null
|
||||
}
|
||||
await this.getDTAddress(account, poolAddress)
|
||||
return super.getSpotPrice(account, poolAddress, this.dtAddress, this.oceanAddress)
|
||||
}
|
||||
|
||||
/**
|
||||
* Search all pools that have DT in their composition
|
||||
* @param {String} account
|
||||
* @param {String} dtAddress
|
||||
* @return {String[]}
|
||||
*/
|
||||
public async searchPoolforDT(account: string, dtAddress: string): Promise<string[]> {
|
||||
const result: string[] = []
|
||||
const factory = new this.web3.eth.Contract(this.FactoryABI, this.factoryAddress, {
|
||||
from: account
|
||||
})
|
||||
const events = await factory.getPastEvents('SPoolRegistered', {
|
||||
filter: {},
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
})
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
const constituents = await super.getCurrentTokens(
|
||||
account,
|
||||
events[i].returnValues[0]
|
||||
)
|
||||
if (constituents.includes(dtAddress)) result.push(events[i].returnValues[0])
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
4105
src/balancer/artifacts/BFactory.json
Normal file
4105
src/balancer/artifacts/BFactory.json
Normal file
File diff suppressed because one or more lines are too long
61759
src/balancer/artifacts/BPool.json
Normal file
61759
src/balancer/artifacts/BPool.json
Normal file
File diff suppressed because one or more lines are too long
3988
src/balancer/artifacts/SFactory.json
Normal file
3988
src/balancer/artifacts/SFactory.json
Normal file
File diff suppressed because one or more lines are too long
63563
src/balancer/artifacts/SPool.json
Normal file
63563
src/balancer/artifacts/SPool.json
Normal file
File diff suppressed because one or more lines are too long
860
src/balancer/balancerlib.ts
Normal file
860
src/balancer/balancerlib.ts
Normal file
@ -0,0 +1,860 @@
|
||||
// import * as jsonFactoryABI from './artifacts/SFactory.json'
|
||||
// import * as jsonPoolABI from './artifacts/SPool.json'
|
||||
|
||||
import * as jsonFactoryABI from '@oceanprotocol/contracts/artifacts/development/SFactory.json'
|
||||
import * as jsonPoolABI from '@oceanprotocol/contracts/artifacts/development/SPool.json'
|
||||
|
||||
/**
|
||||
* Provides a interface to Balancer BPool & BFactory
|
||||
|
||||
*/
|
||||
|
||||
export interface TokensToAdd {
|
||||
address: string
|
||||
amount: string
|
||||
weight: string
|
||||
}
|
||||
|
||||
export class PoolFactory {
|
||||
public GASLIMIT_DEFAULT: number = 5000000
|
||||
public web3: any = null
|
||||
public FactoryABI: any
|
||||
public factoryAddress: any
|
||||
constructor(
|
||||
web3: any,
|
||||
FactoryABI: any = null,
|
||||
factoryAddress: string = null,
|
||||
gaslimit?: number
|
||||
) {
|
||||
this.web3 = web3
|
||||
|
||||
if (FactoryABI) this.FactoryABI = FactoryABI
|
||||
else this.FactoryABI = jsonFactoryABI.abi
|
||||
if (factoryAddress) {
|
||||
this.factoryAddress = factoryAddress
|
||||
}
|
||||
if (gaslimit) this.GASLIMIT_DEFAULT = gaslimit
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new pool
|
||||
*/
|
||||
async createPool(account: string): Promise<string> {
|
||||
if (this.web3 == null) {
|
||||
console.error('Web3 object is null')
|
||||
return null
|
||||
}
|
||||
if (this.factoryAddress == null) {
|
||||
console.error('bfactoryAddress is null')
|
||||
return null
|
||||
}
|
||||
const factory = new this.web3.eth.Contract(this.FactoryABI, this.factoryAddress, {
|
||||
from: account
|
||||
})
|
||||
const transactiondata = await factory.methods
|
||||
.newSPool()
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
let pooladdress = null
|
||||
try {
|
||||
pooladdress = transactiondata.events.SPoolRegistered.returnValues[0]
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return pooladdress
|
||||
}
|
||||
}
|
||||
|
||||
export class Pool extends PoolFactory {
|
||||
private PoolABI: any
|
||||
|
||||
constructor(
|
||||
web3: any,
|
||||
FactoryABI: any = null,
|
||||
PoolABI: any = null,
|
||||
factoryAddress: string = null,
|
||||
gaslimit?: number
|
||||
) {
|
||||
super(web3, FactoryABI, factoryAddress, gaslimit)
|
||||
if (PoolABI) this.PoolABI = PoolABI
|
||||
else this.PoolABI = jsonPoolABI.abi
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new pool
|
||||
*/
|
||||
async createPool(account: string): Promise<string> {
|
||||
const pooladdress = await super.createPool(account)
|
||||
return pooladdress
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve spender to spent amount tokens
|
||||
* @param {String} account
|
||||
* @param {String} tokenAddress
|
||||
* @param {String} spender
|
||||
* @param {String} amount (always expressed as wei)
|
||||
*/
|
||||
async approve(
|
||||
account: string,
|
||||
tokenAddress: string,
|
||||
spender: string,
|
||||
amount: string
|
||||
): Promise<any> {
|
||||
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'
|
||||
}
|
||||
]
|
||||
const token = new this.web3.eth.Contract(minABI, tokenAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await token.methods
|
||||
.approve(spender, amount)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Pool shares
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
|
||||
*/
|
||||
async sharesBalance(account: string, poolAddress: string): Promise<any> {
|
||||
const minABI = [
|
||||
{
|
||||
constant: true,
|
||||
inputs: [
|
||||
{
|
||||
name: '_owner',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
name: 'balanceOf',
|
||||
outputs: [
|
||||
{
|
||||
name: 'balance',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
const token = new this.web3.eth.Contract(minABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = this.web3.utils.fromWei(
|
||||
await token.methods
|
||||
.balanceOf(account)
|
||||
.call({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tokens to pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {Array} tokens Array of token object { address,amount,weight}
|
||||
*/
|
||||
async addToPool(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokens: TokensToAdd[]
|
||||
): Promise<void> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
|
||||
let token
|
||||
for (token of tokens) {
|
||||
try {
|
||||
// approve spending first
|
||||
await this.approve(
|
||||
account,
|
||||
token.address,
|
||||
poolAddress,
|
||||
this.web3.utils.toWei(token.amount)
|
||||
)
|
||||
await pool.methods
|
||||
.bind(
|
||||
token.address,
|
||||
this.web3.utils.toWei(token.amount),
|
||||
this.web3.utils.toWei(token.weight)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pool fee
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} fee (will be converted to wei)
|
||||
*/
|
||||
async setSwapFee(account: string, poolAddress: string, fee: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.setSwapFee(this.web3.utils.toWei(fee))
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize a pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
*/
|
||||
async finalize(account: string, poolAddress: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.finalize()
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of tokens composing this pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
*/
|
||||
async getNumTokens(account: string, poolAddress: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods.getNumTokens().call()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tokens composing this pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {Array}
|
||||
*/
|
||||
async getCurrentTokens(account: string, poolAddress: string): Promise<string[]> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods.getCurrentTokens().call()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the final tokens composing this pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {Array}
|
||||
*/
|
||||
async getFinalTokens(account: string, poolAddress: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods.getFinalTokens().call()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get controller address of this pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {String}
|
||||
*/
|
||||
async getController(account: string, poolAddress: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods.getController().call()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Set controller address of this pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} controllerAddress
|
||||
* @return {String}
|
||||
*/
|
||||
async setController(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
controllerAddress: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.setController(controllerAddress)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if a token is bounded to a pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} token Address of the token
|
||||
* @return {Boolean}
|
||||
*/
|
||||
async isBound(account: string, poolAddress: string, token: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods.isBound(token).call()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get how many tokens are in the pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} token Address of the token
|
||||
* @return {Boolean}
|
||||
*/
|
||||
async getReserve(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
token: string
|
||||
): Promise<string> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let amount = null
|
||||
try {
|
||||
const result = await pool.methods.getBalance(token).call()
|
||||
amount = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return amount
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if a pool is finalized
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {Boolean}
|
||||
*/
|
||||
async isFinalized(account: string, poolAddress: string): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods.isFinalized().call()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pool fee
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {String} Swap fee in wei
|
||||
*/
|
||||
async getSwapFee(account: string, poolAddress: string): Promise<string> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let fee = null
|
||||
try {
|
||||
const result = await pool.methods.getSwapFee().call()
|
||||
fee = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return fee
|
||||
}
|
||||
|
||||
/**
|
||||
* The normalized weight of a token. The combined normalized weights of all tokens will sum up to 1. (Note: the actual sum may be 1 plus or minus a few wei due to division precision loss)
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} token
|
||||
* @return {Number}
|
||||
*/
|
||||
async getNormalizedWeight(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
token: string
|
||||
): Promise<string> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let weight = null
|
||||
try {
|
||||
const result = await pool.methods.getNormalizedWeight(token).call()
|
||||
weight = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
/**
|
||||
* getDenormalizedWeight of a token in pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} token
|
||||
* @return {Number}
|
||||
*/
|
||||
async getDenormalizedWeight(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
token: string
|
||||
): Promise<string> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let weight = null
|
||||
try {
|
||||
const result = await pool.methods.getDenormalizedWeight(token).call()
|
||||
weight = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
/**
|
||||
* getTotalDenormalizedWeight in pool
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @return {String}
|
||||
*/
|
||||
async getTotalDenormalizedWeight(
|
||||
account: string,
|
||||
poolAddress: string
|
||||
): Promise<string> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let weight = null
|
||||
try {
|
||||
const result = await pool.methods.getTotalDenormalizedWeight().call()
|
||||
weight = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
/**
|
||||
* swapExactAmountIn - Trades an exact tokenAmountIn of tokenIn taken from the caller by the pool, in exchange for at least minAmountOut of tokenOut given to the caller from the pool, with a maximum marginal price of maxPrice. Returns (tokenAmountOut, spotPriceAfter), where tokenAmountOut is the amount of token that came out of the pool, and spotPriceAfter is the new marginal spot price, ie, the result of getSpotPrice after the call. (These values are what are limited by the arguments; you are guaranteed tokenAmountOut >= minAmountOut and spotPriceAfter <= maxPrice).
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenIn
|
||||
* @param {String} tokenAmountIn will be converted to wei
|
||||
* @param {String} tokenOut
|
||||
* @param {String} minAmountOut will be converted to wei
|
||||
* @param {String} maxPrice will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async swapExactAmountIn(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenIn: string,
|
||||
tokenAmountIn: string,
|
||||
tokenOut: string,
|
||||
minAmountOut: string,
|
||||
maxPrice: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.swapExactAmountIn(
|
||||
tokenIn,
|
||||
this.web3.utils.toWei(tokenAmountIn),
|
||||
tokenOut,
|
||||
this.web3.utils.toWei(minAmountOut),
|
||||
this.web3.utils.toWei(maxPrice)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* swapExactAmountOut
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenIn
|
||||
* @param {String} maxAmountIn will be converted to wei
|
||||
* @param {String} tokenOut
|
||||
* @param {String} minAmountOut will be converted to wei
|
||||
* @param {String} maxPrice will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async swapExactAmountOut(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenIn: string,
|
||||
maxAmountIn: string,
|
||||
tokenOut: string,
|
||||
minAmountOut: string,
|
||||
maxPrice: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.swapExactAmountOut(
|
||||
tokenIn,
|
||||
this.web3.utils.toWei(maxAmountIn),
|
||||
tokenOut,
|
||||
this.web3.utils.toWei(minAmountOut),
|
||||
this.web3.utils.toWei(maxPrice)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the pool, getting poolAmountOut pool tokens. This will pull some of each of the currently trading tokens in the pool, meaning you must have called approve for each token for this pool. These values are limited by the array of maxAmountsIn in the order of the pool tokens.
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} poolAmountOut will be converted to wei
|
||||
* @param {String} maxAmountsIn array holding maxAmount per each token, will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async joinPool(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
poolAmountOut: string,
|
||||
maxAmountsIn: any
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
const weiMaxAmountsIn = []
|
||||
let amount
|
||||
for (amount of maxAmountsIn) {
|
||||
weiMaxAmountsIn.push(this.web3.utils.toWei(amount))
|
||||
}
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.joinPool(this.web3.utils.toWei(poolAmountOut), weiMaxAmountsIn)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the pool, paying poolAmountIn pool tokens and getting some of each of the currently trading tokens in return. These values are limited by the array of minAmountsOut in the order of the pool tokens.
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} poolAmountIn will be converted to wei
|
||||
* @param {String} maxAmountsIn array holding maxAmount per each token, will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async exitPool(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
poolAmountIn: string,
|
||||
minAmountsOut: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
const weiMinAmountsOut = []
|
||||
let amount
|
||||
for (amount of minAmountsOut) {
|
||||
weiMinAmountsOut.push(this.web3.utils.toWei(amount))
|
||||
}
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.exitPool(this.web3.utils.toWei(poolAmountIn), weiMinAmountsOut)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Pay tokenAmountIn of token tokenIn to join the pool, getting poolAmountOut of the pool shares.
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenIn
|
||||
* @param {String} tokenAmountIn will be converted to wei
|
||||
* @param {String} minPoolAmountOut will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async joinswapExternAmountIn(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenIn: string,
|
||||
tokenAmountIn: string,
|
||||
minPoolAmountOut: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.joinswapExternAmountIn(
|
||||
tokenIn,
|
||||
this.web3.utils.toWei(tokenAmountIn),
|
||||
this.web3.utils.toWei(minPoolAmountOut)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify poolAmountOut pool shares that you want to get, and a token tokenIn to pay with. This costs tokenAmountIn tokens (these went into the pool).
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenIn
|
||||
* @param {String} poolAmountOut will be converted to wei
|
||||
* @param {String} maxAmountIn will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async joinswapPoolAmountOut(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenIn: string,
|
||||
poolAmountOut: string,
|
||||
maxAmountIn: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.joinswapPoolAmountOut(
|
||||
tokenIn,
|
||||
this.web3.utils.toWei(poolAmountOut),
|
||||
this.web3.utils.toWei(maxAmountIn)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Pay poolAmountIn pool shares into the pool, getting minTokenAmountOut of the given token tokenOut out of the pool.
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenOut
|
||||
* @param {String} poolAmountIn will be converted to wei
|
||||
* @param {String} minTokenAmountOut will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async exitswapPoolAmountIn(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenOut: string,
|
||||
poolAmountIn: string,
|
||||
minTokenAmountOut: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.exitswapPoolAmountIn(
|
||||
tokenOut,
|
||||
this.web3.utils.toWei(poolAmountIn),
|
||||
this.web3.utils.toWei(minTokenAmountOut)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify tokenAmountOut of token tokenOut that you want to get out of the pool. This costs poolAmountIn pool shares (these went into the pool).
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenOut
|
||||
* @param {String} tokenAmountOut will be converted to wei
|
||||
* @param {String} maxPoolAmountIn will be converted to wei
|
||||
* @return {any}
|
||||
*/
|
||||
async exitswapExternAmountOut(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenOut: string,
|
||||
tokenAmountOut: string,
|
||||
maxPoolAmountIn: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let result = null
|
||||
try {
|
||||
result = await pool.methods
|
||||
.exitswapExternAmountOut(
|
||||
tokenOut,
|
||||
this.web3.utils.toWei(tokenAmountOut),
|
||||
this.web3.utils.toWei(maxPoolAmountIn)
|
||||
)
|
||||
.send({ from: account, gas: this.GASLIMIT_DEFAULT })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Spot Price of swaping tokenIn to tokenOut
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenIn
|
||||
* @param {String} tokenOut
|
||||
* @return {any}
|
||||
*/
|
||||
async getSpotPrice(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenIn: string,
|
||||
tokenOut: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let price = null
|
||||
try {
|
||||
const result = await pool.methods.getSpotPrice(tokenIn, tokenOut).call()
|
||||
price = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return price
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Spot Price of swaping tokenIn to tokenOut without fees
|
||||
* @param {String} account
|
||||
* @param {String} poolAddress
|
||||
* @param {String} tokenIn
|
||||
* @param {String} tokenOut
|
||||
* @return {any}
|
||||
*/
|
||||
async getSpotPriceSansFee(
|
||||
account: string,
|
||||
poolAddress: string,
|
||||
tokenIn: string,
|
||||
tokenOut: string
|
||||
): Promise<any> {
|
||||
const pool = new this.web3.eth.Contract(this.PoolABI, poolAddress, {
|
||||
from: account
|
||||
})
|
||||
let price = null
|
||||
try {
|
||||
const result = await pool.methods
|
||||
.getSpotPriceSansFee(tokenIn, tokenOut)
|
||||
.call()
|
||||
price = this.web3.utils.fromWei(result)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return price
|
||||
}
|
||||
}
|
@ -56,6 +56,24 @@ export class Config {
|
||||
*/
|
||||
public datatokensABI?: object
|
||||
|
||||
/**
|
||||
* Pool Factory address
|
||||
* @type {string}
|
||||
*/
|
||||
public poolFactoryAddress?: string
|
||||
|
||||
/**
|
||||
* Pool Factory ABI
|
||||
* @type {string}
|
||||
*/
|
||||
public poolFactoryABI?: object
|
||||
|
||||
/**
|
||||
* Pool ABI
|
||||
* @type {string}
|
||||
*/
|
||||
public poolABI?: object
|
||||
|
||||
/**
|
||||
* Log level.
|
||||
* @type {boolean | LogLevel}
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
generateIntantiableConfigFromConfig
|
||||
} from '../Instantiable.abstract'
|
||||
import { Compute } from './Compute'
|
||||
import { OceanPool } from '../balancer/OceanPool'
|
||||
|
||||
/**
|
||||
* Main interface for Ocean Protocol.
|
||||
@ -55,6 +56,13 @@ export class Ocean extends Instantiable {
|
||||
instanceConfig.config.datatokensABI,
|
||||
instanceConfig.config.web3Provider
|
||||
)
|
||||
instance.pool = new OceanPool(
|
||||
instanceConfig.config.web3Provider,
|
||||
instanceConfig.config.poolFactoryABI,
|
||||
instanceConfig.config.poolABI,
|
||||
instanceConfig.config.poolFactoryAddress,
|
||||
instanceConfig.config.oceanTokenAddress
|
||||
)
|
||||
instance.versions = await Versions.getInstance(instanceConfig)
|
||||
instance.network = new Network()
|
||||
return instance
|
||||
@ -110,11 +118,17 @@ export class Ocean extends Instantiable {
|
||||
public compute: Compute
|
||||
|
||||
/**
|
||||
* Ocean secretStore submodule
|
||||
* @type {OceanSecretStore}
|
||||
* Ocean DataTokens submodule
|
||||
* @type {DataTokens}
|
||||
*/
|
||||
public datatokens: DataTokens
|
||||
|
||||
/**
|
||||
* Ocean Pools submodule
|
||||
* @type {OceanPool}
|
||||
*/
|
||||
public pool: OceanPool
|
||||
|
||||
/**
|
||||
* Ocean tokens submodule
|
||||
* @type {OceanTokens}
|
||||
|
@ -2,6 +2,7 @@ export interface ConfigHelper {
|
||||
network: string
|
||||
url: string
|
||||
factoryAddress: string
|
||||
poolFactoryAddress: string
|
||||
oceanTokenAddress: string
|
||||
metadataStoreUri: string
|
||||
providerUri: string
|
||||
@ -13,15 +14,8 @@ const configs = [
|
||||
url: 'http://localhost:8545',
|
||||
factoryAddress: null,
|
||||
metadataStoreUri: 'http://127.0.0.1:5000',
|
||||
providerUri: 'http://127.0.0.1:8030'
|
||||
},
|
||||
{
|
||||
network: 'pacific',
|
||||
url: 'https://pacific.oceanprotocol.com',
|
||||
factoryAddress: '0x1234',
|
||||
oceanTokenAddress: '0x012578f9381e876A9E2a9111Dfd436FF91A451ae',
|
||||
metadataStoreUri: null,
|
||||
providerUri: null
|
||||
providerUri: 'http://127.0.0.1:8030',
|
||||
poolFactoryAddress: null
|
||||
},
|
||||
{
|
||||
network: 'rinkeby',
|
||||
@ -29,7 +23,8 @@ const configs = [
|
||||
factoryAddress: '0xcDfEe5D80041224cDCe9AE2334E85B3236385EA3',
|
||||
oceanTokenAddress: '0x8967BCF84170c91B0d24D4302C2376283b0B3a07',
|
||||
metadataStoreUri: 'https://aquarius.rinkeby.v3.dev-ocean.com/',
|
||||
providerUri: 'https://provider.rinkeby.v3.dev-ocean.com/'
|
||||
providerUri: 'https://provider.rinkeby.v3.dev-ocean.com/',
|
||||
poolFactoryAddress: '0xA4531C624A3D88323a1e178DABe1233AF178701B'
|
||||
},
|
||||
{
|
||||
network: 'mainnet',
|
||||
@ -37,7 +32,8 @@ const configs = [
|
||||
factoryAddress: '0x1234',
|
||||
oceanTokenAddress: '0x985dd3d42de1e256d09e1c10f112bccb8015ad41',
|
||||
metadataStoreUri: null,
|
||||
providerUri: null
|
||||
providerUri: null,
|
||||
poolFactoryAddress: null
|
||||
}
|
||||
]
|
||||
|
||||
@ -51,7 +47,7 @@ export class ConfigHelper {
|
||||
confighelp.oceanTokenAddress = null
|
||||
confighelp.metadataStoreUri = null
|
||||
confighelp.providerUri = null
|
||||
|
||||
confighelp.poolFactoryAddress = null
|
||||
const knownconfig = configs.find((c) => c.network === network)
|
||||
if (knownconfig) {
|
||||
confighelp.factoryAddress = knownconfig.factoryAddress
|
||||
@ -60,6 +56,7 @@ export class ConfigHelper {
|
||||
confighelp.network = knownconfig.network
|
||||
confighelp.metadataStoreUri = knownconfig.metadataStoreUri
|
||||
confighelp.providerUri = knownconfig.providerUri
|
||||
confighelp.poolFactoryAddress = knownconfig.poolFactoryAddress
|
||||
}
|
||||
return confighelp
|
||||
}
|
||||
|
106
test/BalancerContractHandler.ts
Normal file
106
test/BalancerContractHandler.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
|
||||
export class BalancerContractHandler {
|
||||
public factory: Contract
|
||||
public pool: Contract
|
||||
public accounts: string[]
|
||||
public poolBytecode: string
|
||||
public factoryBytecode: string
|
||||
public factoryAddress: string
|
||||
public poolAddress: string
|
||||
public web3: any
|
||||
|
||||
constructor(
|
||||
factoryABI: Contract,
|
||||
factoryBytecode: string,
|
||||
poolABI: Contract,
|
||||
poolBytecode: string,
|
||||
web3: any
|
||||
) {
|
||||
this.web3 = web3
|
||||
this.factory = new this.web3.eth.Contract(factoryABI)
|
||||
this.factoryBytecode = factoryBytecode
|
||||
this.pool = new this.web3.eth.Contract(poolABI)
|
||||
this.poolBytecode = poolBytecode
|
||||
}
|
||||
|
||||
public async getAccounts() {
|
||||
this.accounts = await this.web3.eth.getAccounts()
|
||||
}
|
||||
|
||||
public async deployContracts(minter: string) {
|
||||
const estGas = await this.factory
|
||||
.deploy({
|
||||
data: this.factoryBytecode,
|
||||
arguments: []
|
||||
})
|
||||
.estimateGas(function (err, estGas) {
|
||||
if (err) console.log('DeployContracts: ' + err)
|
||||
return estGas
|
||||
})
|
||||
// deploy the contract and get it's address
|
||||
this.factoryAddress = await this.factory
|
||||
.deploy({
|
||||
data: this.factoryBytecode,
|
||||
arguments: []
|
||||
})
|
||||
.send({
|
||||
from: minter,
|
||||
gas: estGas + 1,
|
||||
gasPrice: '3000000000'
|
||||
})
|
||||
.then(function (contract) {
|
||||
return contract.options.address
|
||||
})
|
||||
}
|
||||
|
||||
public async SdeployContracts(minter: string) {
|
||||
let estGas
|
||||
estGas = await this.pool
|
||||
.deploy({
|
||||
data: this.poolBytecode,
|
||||
arguments: []
|
||||
})
|
||||
.estimateGas(function (err, estGas) {
|
||||
if (err) console.log('Pool deploy estimate gas: ' + err)
|
||||
return estGas
|
||||
})
|
||||
// deploy the contract and get it's address
|
||||
this.poolAddress = await this.pool
|
||||
.deploy({
|
||||
data: this.poolBytecode,
|
||||
arguments: []
|
||||
})
|
||||
.send({
|
||||
from: minter,
|
||||
gas: estGas + 1,
|
||||
gasPrice: '3000000000'
|
||||
})
|
||||
.then(function (contract) {
|
||||
return contract.options.address
|
||||
})
|
||||
estGas = await this.factory
|
||||
.deploy({
|
||||
data: this.factoryBytecode,
|
||||
arguments: [this.poolAddress]
|
||||
})
|
||||
.estimateGas(function (err, estGas) {
|
||||
if (err) console.log('DeployContracts: ' + err)
|
||||
return estGas
|
||||
})
|
||||
// deploy the contract and get it's address
|
||||
this.factoryAddress = await this.factory
|
||||
.deploy({
|
||||
data: this.factoryBytecode,
|
||||
arguments: [this.poolAddress]
|
||||
})
|
||||
.send({
|
||||
from: minter,
|
||||
gas: estGas + 1,
|
||||
gasPrice: '3000000000'
|
||||
})
|
||||
.then(function (contract) {
|
||||
return contract.options.address
|
||||
})
|
||||
}
|
||||
}
|
240
test/unit/balancer/Balancer.test.ts
Normal file
240
test/unit/balancer/Balancer.test.ts
Normal file
@ -0,0 +1,240 @@
|
||||
import { assert } from 'chai'
|
||||
import { TestContractHandler } from '../../TestContractHandler'
|
||||
import { BalancerContractHandler } from '../../BalancerContractHandler'
|
||||
import { DataTokens } from '../../../src/datatokens/Datatokens'
|
||||
import { OceanPool } from '../../../src/balancer/OceanPool'
|
||||
|
||||
const Web3 = require('web3')
|
||||
const web3 = new Web3('http://127.0.0.1:8545')
|
||||
const factory = require('@oceanprotocol/contracts/artifacts/development/DTFactory.json')
|
||||
const datatokensTemplate = require('@oceanprotocol/contracts/artifacts/development/DataTokenTemplate.json')
|
||||
|
||||
// this will be replaced by our SFactory/SPool
|
||||
const OceanPoolFactory = require('@oceanprotocol/contracts/artifacts/development/SFactory.json')
|
||||
const OceanSPool = require('@oceanprotocol/contracts/artifacts/development/SPool.json')
|
||||
|
||||
describe('Balancer flow', () => {
|
||||
let oceanTokenAddress
|
||||
let OceanPoolFactoryAddress
|
||||
let Pool
|
||||
let oceandatatoken
|
||||
let alicePoolAddress
|
||||
let currentDtPrice
|
||||
let owner
|
||||
let bob
|
||||
let alice
|
||||
let contracts
|
||||
let datatoken
|
||||
let tokenAddress
|
||||
let consoleDebug: false
|
||||
let greatPool
|
||||
const tokenAmount = '1000'
|
||||
const transferAmount = '200'
|
||||
const blob = 'http://localhost:8030/api/v1/services/consume'
|
||||
describe('#test', () => {
|
||||
before(async () => {
|
||||
// deploy SFactory
|
||||
const SContracts = new BalancerContractHandler(
|
||||
OceanPoolFactory.abi,
|
||||
OceanPoolFactory.bytecode,
|
||||
OceanSPool.abi,
|
||||
OceanSPool.bytecode,
|
||||
web3
|
||||
)
|
||||
await SContracts.getAccounts()
|
||||
owner = SContracts.accounts[0]
|
||||
|
||||
await SContracts.SdeployContracts(owner)
|
||||
OceanPoolFactoryAddress = SContracts.factoryAddress
|
||||
assert(OceanPoolFactoryAddress !== null)
|
||||
|
||||
// deploy DT Factory
|
||||
contracts = new TestContractHandler(
|
||||
factory.abi,
|
||||
datatokensTemplate.abi,
|
||||
datatokensTemplate.bytecode,
|
||||
factory.bytecode,
|
||||
web3
|
||||
)
|
||||
await contracts.getAccounts()
|
||||
owner = contracts.accounts[0]
|
||||
alice = contracts.accounts[1]
|
||||
bob = contracts.accounts[2]
|
||||
await contracts.deployContracts(owner)
|
||||
|
||||
// initialize DataTokens
|
||||
datatoken = new DataTokens(
|
||||
contracts.factoryAddress,
|
||||
factory.abi,
|
||||
datatokensTemplate.abi,
|
||||
web3
|
||||
)
|
||||
assert(datatoken !== null)
|
||||
})
|
||||
|
||||
it('should create datatokens smart contract', async () => {
|
||||
tokenAddress = await datatoken.create(blob, alice)
|
||||
assert(tokenAddress !== null)
|
||||
})
|
||||
it('Create a dummy OceanToken', async () => {
|
||||
// Alice creates a Datatoken
|
||||
oceandatatoken = new DataTokens(
|
||||
contracts.factoryAddress,
|
||||
factory.abi,
|
||||
datatokensTemplate.abi,
|
||||
web3
|
||||
)
|
||||
oceanTokenAddress = await oceandatatoken.create(blob, alice)
|
||||
})
|
||||
it('should initialize OceanPool class', async () => {
|
||||
Pool = new OceanPool(
|
||||
web3,
|
||||
OceanPoolFactory.abi,
|
||||
OceanSPool.abi,
|
||||
OceanPoolFactoryAddress,
|
||||
oceanTokenAddress
|
||||
)
|
||||
assert(Pool !== null)
|
||||
})
|
||||
|
||||
it('Alice mints 1000 tokens', async () => {
|
||||
await datatoken.mint(tokenAddress, alice, tokenAmount)
|
||||
})
|
||||
it('Alice mints 1000 Ocean tokens', async () => {
|
||||
await oceandatatoken.mint(oceanTokenAddress, alice, tokenAmount)
|
||||
})
|
||||
it('Alice transfers 200 ocean token to Bob', async () => {
|
||||
const ts = await datatoken.transfer(
|
||||
oceanTokenAddress,
|
||||
bob,
|
||||
transferAmount,
|
||||
alice
|
||||
)
|
||||
})
|
||||
it('Alice creates a new OceanPool pool', async () => {
|
||||
/// new pool with total DT = 45 , dt weight=90% with swap fee 2%
|
||||
alicePoolAddress = await Pool.createDTPool(alice, tokenAddress, 45, 9, '0.02')
|
||||
})
|
||||
it('Get pool information', async () => {
|
||||
const currentTokens = await Pool.getCurrentTokens(alice, alicePoolAddress)
|
||||
assert(currentTokens.length === 2)
|
||||
assert(currentTokens.includes(tokenAddress))
|
||||
assert(currentTokens.includes(oceanTokenAddress))
|
||||
})
|
||||
it('Get pool swap fee', async () => {
|
||||
const currentSwapFee = await Pool.getSwapFee(alice, alicePoolAddress)
|
||||
assert(currentSwapFee === '0.02')
|
||||
})
|
||||
it('Get dtPrice from the pool ', async () => {
|
||||
currentDtPrice = await Pool.getDTPrice(alice, alicePoolAddress)
|
||||
assert(currentDtPrice > 0)
|
||||
})
|
||||
it('Get dtToken pool reserve ', async () => {
|
||||
const currentDtReserve = await Pool.getDTReserve(alice, alicePoolAddress)
|
||||
assert(currentDtReserve > 0)
|
||||
})
|
||||
it('Get dtToken pool reserve ', async () => {
|
||||
const currentOceanReserve = await Pool.getOceanReserve(
|
||||
alice,
|
||||
alicePoolAddress
|
||||
)
|
||||
assert(currentOceanReserve > 0)
|
||||
})
|
||||
it('Bob should search for pools with this DT', async () => {
|
||||
const pools = await Pool.searchPoolforDT(bob, tokenAddress)
|
||||
assert(pools.length > 0)
|
||||
greatPool = pools[0]
|
||||
})
|
||||
it('Bob should buy a DT ', async () => {
|
||||
const maxPrice = parseFloat(currentDtPrice) * 2
|
||||
await Pool.buyDT(bob, greatPool, '1', '2', String(maxPrice))
|
||||
const bobDtBalance = await datatoken.balance(tokenAddress, bob)
|
||||
const bobOceanBalance = await datatoken.balance(oceanTokenAddress, bob)
|
||||
assert(bobDtBalance > 0)
|
||||
assert(bobOceanBalance > 0)
|
||||
})
|
||||
it('Bob should add DT liquidity to pool ', async () => {
|
||||
const currentDtReserve = await Pool.getDTReserve(bob, greatPool)
|
||||
if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve)
|
||||
const bobDtBalance = await datatoken.balance(tokenAddress, bob)
|
||||
if (consoleDebug) console.log('BOB DT Balance:' + bobDtBalance)
|
||||
await Pool.addDTLiquidity(bob, greatPool, bobDtBalance)
|
||||
|
||||
const newbobDtBalance = await datatoken.balance(tokenAddress, bob)
|
||||
|
||||
const newDtReserve = await Pool.getDTReserve(bob, greatPool)
|
||||
|
||||
const sharesBalance = await Pool.sharesBalance(bob, greatPool)
|
||||
if (consoleDebug) console.log('newDtReserve:' + newDtReserve)
|
||||
if (consoleDebug) console.log('newbobDtBalance:' + newbobDtBalance)
|
||||
if (consoleDebug) console.log('sharesBalance:' + sharesBalance)
|
||||
assert(parseFloat(newbobDtBalance) < parseFloat(bobDtBalance))
|
||||
assert(parseFloat(newDtReserve) > parseFloat(currentDtReserve))
|
||||
assert(parseFloat(sharesBalance) > 0)
|
||||
})
|
||||
|
||||
it('Bob should remove DT liquidity from pool ', async () => {
|
||||
const currentDtReserve = await Pool.getDTReserve(bob, greatPool)
|
||||
if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve)
|
||||
const bobDtBalance = await datatoken.balance(tokenAddress, bob)
|
||||
if (consoleDebug) console.log('bobDtBalance:' + bobDtBalance)
|
||||
const poolShares = await Pool.sharesBalance(bob, greatPool)
|
||||
if (consoleDebug) console.log('poolShares:' + poolShares)
|
||||
await Pool.removeDTLiquidity(bob, greatPool, '0.75', poolShares)
|
||||
|
||||
const newDtReserve = await Pool.getDTReserve(bob, greatPool)
|
||||
if (consoleDebug) console.log('newDtReserve:' + newDtReserve)
|
||||
const newbobDtBalance = await datatoken.balance(tokenAddress, bob)
|
||||
if (consoleDebug) console.log('newbobDtBalance:' + newbobDtBalance)
|
||||
const newpoolShares = await Pool.sharesBalance(bob, greatPool)
|
||||
if (consoleDebug) console.log('newpoolShares:' + newpoolShares)
|
||||
assert(parseFloat(newDtReserve) < parseFloat(currentDtReserve))
|
||||
assert(parseFloat(bobDtBalance) < parseFloat(newbobDtBalance))
|
||||
assert(parseFloat(poolShares) > parseFloat(newpoolShares))
|
||||
})
|
||||
|
||||
it('Bob should add Ocean liquidity to pool ', async () => {
|
||||
const currentDtReserve = await Pool.getOceanReserve(bob, greatPool)
|
||||
const bobDtBalance = await datatoken.balance(oceanTokenAddress, bob)
|
||||
if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve)
|
||||
if (consoleDebug) console.log('bobDtBalance:' + bobDtBalance)
|
||||
|
||||
await Pool.addOceanLiquidity(bob, greatPool, '1')
|
||||
|
||||
const newbobDtBalance = await datatoken.balance(oceanTokenAddress, bob)
|
||||
|
||||
const newDtReserve = await Pool.getOceanReserve(bob, greatPool)
|
||||
|
||||
const sharesBalance = await Pool.sharesBalance(bob, greatPool)
|
||||
if (consoleDebug) console.log('newDtReserve:' + newDtReserve)
|
||||
if (consoleDebug) console.log('newbobDtBalance:' + newbobDtBalance)
|
||||
if (consoleDebug) console.log('sharesBalance:' + sharesBalance)
|
||||
assert(parseFloat(newbobDtBalance) < parseFloat(bobDtBalance))
|
||||
assert(parseFloat(newDtReserve) > parseFloat(currentDtReserve))
|
||||
assert(parseFloat(sharesBalance) > 0)
|
||||
})
|
||||
|
||||
it('Bob should remove Ocean liquidity from pool ', async () => {
|
||||
const currentDtReserve = await Pool.getOceanReserve(bob, greatPool)
|
||||
const bobDtBalance = await datatoken.balance(oceanTokenAddress, bob)
|
||||
|
||||
const poolShares = await Pool.sharesBalance(bob, greatPool)
|
||||
if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve)
|
||||
if (consoleDebug) console.log('bobDtBalance:' + bobDtBalance)
|
||||
if (consoleDebug) console.log('poolShares:' + poolShares)
|
||||
|
||||
await Pool.removeOceanLiquidity(bob, greatPool, '0.75', poolShares)
|
||||
|
||||
const newDtReserve = await Pool.getOceanReserve(bob, greatPool)
|
||||
const newbobDtBalance = await datatoken.balance(oceanTokenAddress, bob)
|
||||
const newpoolShares = await Pool.sharesBalance(bob, greatPool)
|
||||
|
||||
if (consoleDebug) console.log('newDtReserve:' + newDtReserve)
|
||||
if (consoleDebug) console.log('newbobDtBalance:' + newbobDtBalance)
|
||||
if (consoleDebug) console.log('newpoolShares:' + newpoolShares)
|
||||
assert(parseFloat(newDtReserve) < parseFloat(currentDtReserve))
|
||||
assert(parseFloat(bobDtBalance) < parseFloat(newbobDtBalance))
|
||||
assert(parseFloat(poolShares) > parseFloat(newpoolShares))
|
||||
})
|
||||
})
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user