1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00
This commit is contained in:
alexcos20 2020-07-10 00:46:50 -07:00
parent 7c5d10a7e7
commit 40a8149905
6 changed files with 67999 additions and 324 deletions

291
src/balancer/OceanPool.ts Normal file
View File

@ -0,0 +1,291 @@
import { BalancerPool } from './balancerlib'
export class OceanPool extends BalancerPool {
/** Ocean related functions */
public oceanAddress: string = null
public dtAddress: string = null
constructor(
web3: any,
account: string,
FactoryABI: any = null,
PoolABI: any = null,
factoryAddress: string = null,
oceanAddress: string = null
) {
super(web3, account, FactoryABI, PoolABI, factoryAddress)
if (oceanAddress) {
this.oceanAddress = oceanAddress
}
}
/* async getNetworkAddresses(): Promise<void> {
if (this.factoryAddress && this.oceanAddress) {
return
}
const netId = await this.web3.eth.net.getId()
switch (netId) {
case 1:
if (!this.factoryAddress)
this.factoryAddress = '0x9424B1412450D0f8Fc2255FAf6046b98213B76Bd'
if (!this.oceanAddress)
this.oceanAddress = '0x985dd3D42De1e256d09e1c10F112bCCB8015AD41'
break
case 42:
if (!this.factoryAddress)
this.factoryAddress = '0x8f7F78080219d4066A8036ccD30D588B416a40DB'
if (!this.oceanAddress) this.oceanAddress = null
break
default:
this.factoryAddress = null
this.oceanAddress = null
}
} */
/**
* create DataToken pool
* @param {String} token Data Token Address
* @param {String} amount Data Token Amount
* @param {String} weight Data Token Weight
* @return {any}
*/
public async createDTPool(
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.newPool()
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(tokens)
await super.setSwapFee(fee)
if (finalize) await super.finalize()
return address
}
/**
* Load a previous created DataToken pool
* @param {String} address Data Token Address
* @return {any}
*/
public async loadDTPool(address: string): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
await super.loadPool(address)
const tokens = await this.getCurrentTokens()
let token
for (token of tokens) {
if (token !== this.oceanAddress) this.dtAddress = token
}
return this
}
/**
* Get Ocean Token balance of a pool
* @return {any}
*/
public async getOceanBalance(): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
return super.getBalance(this.oceanAddress)
}
/**
* Get Data Token balance of a pool
* @return {any}
*/
public async getDTBalance(): Promise<any> {
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
return super.getBalance(this.dtAddress)
}
/**
* Buy Data Token from a pool
* @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(
amount: string,
oceanAmount: string,
maxPrice: string
): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
// TODO - check balances first
await super.approve(
this.oceanAddress,
this.poolAddress,
this.web3.utils.toWei(oceanAmount)
)
return this.swapExactAmountOut(
this.oceanAddress,
oceanAmount,
this.dtAddress,
amount,
maxPrice
)
}
/**
* Sell Data Token
* @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(
amount: string,
oceanAmount: string,
minPrice: string
): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
return this.swapExactAmountOut(
this.dtAddress,
amount,
this.oceanAddress,
oceanAmount,
minPrice
)
}
/**
* Add Data Token amount to pool liquidity
* @param {String} amount Data Token Amount
* @return {any}
*/
public async addDTLiquidity(amount: string): Promise<any> {
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
await this.approve(
this.dtAddress,
this.poolAddress,
this.web3.utils.toWei(amount)
)
const result = await this.joinswapExternAmountIn(this.dtAddress, amount, '0')
return result
}
/**
* Remove Data Token amount from pool liquidity
* @param {String} amount pool Liquidity Amount
* @return {any}
*/
public removeDTLiquidity(amount: string, maximumPoolShares: string): Promise<any> {
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
// TODO Check balance of PoolShares before doing exit
return this.exitswapExternAmountOut(this.dtAddress, amount, maximumPoolShares)
}
/**
* Add Ocean Token amount to pool liquidity
* @param {String} amount Data Token Amount
* @return {any}
*/
public async addOceanLiquidity(amount: string): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
await this.approve(
this.oceanAddress,
this.poolAddress,
this.web3.utils.toWei(amount)
)
const result = await this.joinswapExternAmountIn(this.oceanAddress, amount, '0')
return result
}
/**
* Remove Ocean Token amount from pool liquidity
* @param {String} amount pool Liquidity Amount
* @return {any}
*/
public removeOceanLiquidity(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 this.exitswapExternAmountOut(this.oceanAddress, amount, maximumPoolShares)
}
/**
* Get Data Token Price from pool
* @return {any}
*/
public async getDTPrice(): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
return this.getSpotPrice(this.dtAddress, this.oceanAddress)
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,6 @@
// import * as jsonFactoryABI from './artifacts/SFactory.json'
// import * as jsonPoolABI from './artifacts/SPool.json'
import * as jsonFactoryABI from './artifacts/BFactory.json'
import * as jsonPoolABI from './artifacts/BPool.json'
@ -12,67 +15,31 @@ export interface TokensToAdd {
weight: string
}
export class Balancer {
private GASLIMIT_DEFAULT: number = 5000000
private web3: any = null
export class BalancerFactory {
public GASLIMIT_DEFAULT: number = 5000000
public web3: any = null
public account: string = null
private FactoryABI: any
private PoolABI: any
private factoryAddress: any
private account: string = null
private pool: any = null
public poolAddress: string = null
public oceanAddress: string = null
public dtAddress: string = null
public factoryAddress: any
constructor(
web3: any,
account: string,
FactoryABI: any = null,
PoolABI: any = null,
factoryAddress: string = null,
oceanAddress: string = null
factoryAddress: string = null
) {
this.web3 = web3
this.account = account
if (FactoryABI) this.FactoryABI = FactoryABI
else this.FactoryABI = jsonFactoryABI.abi
if (PoolABI) this.PoolABI = PoolABI
else this.PoolABI = jsonPoolABI.abi
if (factoryAddress) {
this.factoryAddress = factoryAddress
}
if (oceanAddress) {
this.oceanAddress = oceanAddress
}
}
async getNetworkAddresses(): Promise<void> {
if (this.factoryAddress && this.oceanAddress) {
return
}
const netId = await this.web3.eth.net.getId()
switch (netId) {
case 1:
if (!this.factoryAddress)
this.factoryAddress = '0x9424B1412450D0f8Fc2255FAf6046b98213B76Bd'
if (!this.oceanAddress)
this.oceanAddress = '0x985dd3D42De1e256d09e1c10F112bCCB8015AD41'
break
case 42:
if (!this.factoryAddress)
this.factoryAddress = '0x8f7F78080219d4066A8036ccD30D588B416a40DB'
if (!this.oceanAddress) this.oceanAddress = null
break
default:
this.factoryAddress = null
this.oceanAddress = null
}
}
/**
* Creates a new pool
*/
async newPool(): Promise<string> {
await this.getNetworkAddresses()
if (this.web3 == null) {
console.error('Web3 object is null')
return null
@ -94,13 +61,39 @@ export class Balancer {
let pooladdress = null
try {
pooladdress = transactiondata.events.LOG_NEW_POOL.returnValues[1]
} catch (e) {
console.error(e)
}
return pooladdress
}
}
export class BalancerPool extends BalancerFactory {
private PoolABI: any
private pool: any = null
public poolAddress: string = null
constructor(
web3: any,
account: string,
FactoryABI: any = null,
PoolABI: any = null,
factoryAddress: string = null
) {
super(web3, account, FactoryABI, factoryAddress)
if (PoolABI) this.PoolABI = PoolABI
else this.PoolABI = jsonPoolABI.abi
}
/**
* Creates a new pool
*/
async newPool(): Promise<string> {
const pooladdress = await super.newPool()
this.poolAddress = pooladdress
this.pool = new this.web3.eth.Contract(this.PoolABI, pooladdress, {
from: this.account
})
} catch (e) {
console.error(e)
}
return pooladdress
}
@ -108,7 +101,6 @@ export class Balancer {
* Loads a new pool
*/
async loadPool(address: string): Promise<any> {
await this.getNetworkAddresses()
if (this.web3 == null) {
console.error('Web3 object is null')
return null
@ -814,252 +806,4 @@ export class Balancer {
}
return price
}
/** Ocean related functions */
/**
* create DataToken pool
* @param {String} token Data Token Address
* @param {String} amount Data Token Amount
* @param {String} weight Data Token Weight
* @return {any}
*/
public async createDTPool(
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 this.newPool()
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 this.addToPool(tokens)
await this.setSwapFee(fee)
if (finalize) await this.finalize()
return address
}
/**
* Load a previous created DataToken pool
* @param {String} address Data Token Address
* @return {any}
*/
public async loadDTPool(address: string): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
await this.loadPool(address)
const tokens = await this.getCurrentTokens()
let token
for (token of tokens) {
if (token !== this.oceanAddress) this.dtAddress = token
}
return this
}
/**
* Get Ocean Token balance of a pool
* @return {any}
*/
public async getOceanBalance(): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
return this.getBalance(this.oceanAddress)
}
/**
* Get Data Token balance of a pool
* @return {any}
*/
public async getDTBalance(): Promise<any> {
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
return this.getBalance(this.dtAddress)
}
/**
* Buy Data Token from a pool
* @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(
amount: string,
oceanAmount: string,
maxPrice: string
): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
// TODO - check balances first
await this.approve(
this.oceanAddress,
this.poolAddress,
this.web3.utils.toWei(oceanAmount)
)
return this.swapExactAmountOut(
this.oceanAddress,
oceanAmount,
this.dtAddress,
amount,
maxPrice
)
}
/**
* Sell Data Token
* @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(
amount: string,
oceanAmount: string,
minPrice: string
): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
return this.swapExactAmountOut(
this.dtAddress,
amount,
this.oceanAddress,
oceanAmount,
minPrice
)
}
/**
* Add Data Token amount to pool liquidity
* @param {String} amount Data Token Amount
* @return {any}
*/
public async addDTLiquidity(amount: string): Promise<any> {
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
await this.approve(
this.dtAddress,
this.poolAddress,
this.web3.utils.toWei(amount)
)
const result = await this.joinswapExternAmountIn(this.dtAddress, amount, '0')
return result
}
/**
* Remove Data Token amount from pool liquidity
* @param {String} amount pool Liquidity Amount
* @return {any}
*/
public removeDTLiquidity(amount: string, maximumPoolShares: string): Promise<any> {
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
// TODO Check balance of PoolShares before doing exit
return this.exitswapExternAmountOut(this.dtAddress, amount, maximumPoolShares)
}
/**
* Add Ocean Token amount to pool liquidity
* @param {String} amount Data Token Amount
* @return {any}
*/
public async addOceanLiquidity(amount: string): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
await this.approve(
this.oceanAddress,
this.poolAddress,
this.web3.utils.toWei(amount)
)
const result = await this.joinswapExternAmountIn(this.oceanAddress, amount, '0')
return result
}
/**
* Remove Ocean Token amount from pool liquidity
* @param {String} amount pool Liquidity Amount
* @return {any}
*/
public removeOceanLiquidity(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 this.exitswapExternAmountOut(this.oceanAddress, amount, maximumPoolShares)
}
/**
* Get Data Token Price from pool
* @return {any}
*/
public async getDTPrice(): Promise<any> {
if (this.oceanAddress == null) {
console.error('oceanAddress is not defined')
return null
}
if (this.dtAddress == null) {
console.error(
'dtAddress is not defined. Did you do loadDTPool or createDTPool ?'
)
return null
}
return this.getSpotPrice(this.dtAddress, this.oceanAddress)
}
}

View File

@ -10,10 +10,18 @@ export class BalancerContractHandler {
public poolAddress: string
public web3: any
constructor(factoryABI: Contract, factoryBytecode: string, 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() {
@ -30,6 +38,7 @@ export class BalancerContractHandler {
if (err) console.log('DeployContracts: ' + err)
return estGas
})
console.log('estGas:' + estGas)
// deploy the contract and get it's address
this.factoryAddress = await this.factory
.deploy({
@ -45,4 +54,58 @@ export class BalancerContractHandler {
return contract.options.address
})
}
public async SdeployContracts(minter: string) {
let estGas
estGas = await this.pool
.deploy({
data: this.poolBytecode,
arguments: []
})
.estimateGas({ from: minter, gas: 9007199254740991 }, function (err, estGas) {
if (err) console.log('DeployContracts: ' + err)
return estGas
})
// deploy the contract and get it's address
console.log('estGas:' + estGas)
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
})
console.log('estGas:' + 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
})
}
}

View File

@ -2,7 +2,8 @@ import { assert } from 'chai'
import { TestContractHandler } from '../../TestContractHandler'
import { BalancerContractHandler } from '../../BalancerContractHandler'
import { DataTokens } from '../../../src/datatokens/Datatokens'
import { Balancer } from '../../../src/balancer/balancerlib'
// import { Balancer } from '../../../src/balancer/balancerlib'
import { OceanPool } from '../../../src/balancer/OceanPool'
import { Ocean } from '../../../src/ocean/Ocean'
import { Config } from '../../../src/models/Config'
@ -12,14 +13,17 @@ const factory = require('@oceanprotocol/contracts/artifacts/development/Factory.
const datatokensTemplate = require('@oceanprotocol/contracts/artifacts/development/DataTokenTemplate.json')
// this will be replaced by our SFactory/SPool
const balancerFactory = require('../../../src/balancer/artifacts/BFactory.json')
const balancerPool = require('../../../src/balancer/artifacts/BPool.json')
const SFactory = require('../../../src/balancer/artifacts/SFactory.json')
const SPool = require('../../../src/balancer/artifacts/SPool.json')
const OceanPoolFactory = require('../../../src/balancer/artifacts/BFactory.json')
const OceanPoolPool = require('../../../src/balancer/artifacts/BPool.json')
describe('Balancer flow', () => {
let oceanTokenAddress
let balancerFactoryAddress
let balancer
let balancerContracts
let OceanPoolFactoryAddress
let Pool
let OceanPoolContracts
let oceandatatoken
let alicePool
let alicePoolAddress
@ -75,28 +79,50 @@ describe('Balancer flow', () => {
)
oceanTokenAddress = await oceandatatoken.create(blob, alice)
})
it('Deploy Balancer Factory', async () => {
balancerContracts = new BalancerContractHandler(
balancerFactory.abi,
balancerFactory.bytecode,
it('Deploy OceanPool Factory', async () => {
OceanPoolContracts = new BalancerContractHandler(
OceanPoolFactory.abi,
OceanPoolFactory.bytecode,
OceanPoolPool.abi,
OceanPoolPool.bytecode,
web3
)
await balancerContracts.getAccounts()
owner = balancerContracts.accounts[0]
await balancerContracts.deployContracts(owner)
balancerFactoryAddress = balancerContracts.factoryAddress
assert(balancerFactoryAddress !== null)
await OceanPoolContracts.getAccounts()
owner = OceanPoolContracts.accounts[0]
console.log('Owner:' + owner)
await OceanPoolContracts.deployContracts(owner)
OceanPoolFactoryAddress = OceanPoolContracts.factoryAddress
assert(OceanPoolFactoryAddress !== null)
})
it('should initialize balancer class', async () => {
balancer = new Balancer(
it('Deploy SFactory', async () => {
const SContracts = new BalancerContractHandler(
SFactory.abi,
SFactory.bytecode,
SPool.abi,
SPool.bytecode,
web3
)
await SContracts.getAccounts()
owner = SContracts.accounts[0]
console.log('Owner:' + owner)
await SContracts.SdeployContracts(owner)
const SFactoryAddress = SContracts.factoryAddress
assert(SFactoryAddress !== null)
})
it('should initialize OceanPool class', async () => {
Pool = new OceanPool(
web3,
alice,
balancerFactory.abi,
balancerPool.abi,
balancerFactoryAddress,
OceanPoolFactory.abi,
OceanPoolPool.abi,
OceanPoolFactoryAddress,
oceanTokenAddress
)
assert(balancer !== null)
assert(Pool !== null)
})
it('Alice mints 1000 tokens', async () => {
@ -114,10 +140,10 @@ describe('Balancer flow', () => {
)
transactionId = ts.transactionHash
})
it('Alice creates a new balancer pool', async () => {
it('Alice creates a new OceanPool pool', async () => {
/// new pool with total DT = 45 , dt weight=90% with swap fee 2%
alicePoolAddress = await balancer.createDTPool(tokenAddress, 45, 9, '0.02')
alicePool = await balancer.loadDTPool(alicePoolAddress)
alicePoolAddress = await Pool.createDTPool(tokenAddress, 45, 9, '0.02')
alicePool = await Pool.loadDTPool(alicePoolAddress)
assert(alicePool !== null)
})
it('Get pool information', async () => {
@ -143,12 +169,12 @@ describe('Balancer flow', () => {
assert(currentOceanReserve > 0)
})
it("Bob should load Alice's pool ", async () => {
bobPool = new Balancer(
bobPool = new OceanPool(
web3,
bob,
balancerFactory.abi,
balancerPool.abi,
balancerFactoryAddress,
OceanPoolFactory.abi,
OceanPoolPool.abi,
OceanPoolFactoryAddress,
oceanTokenAddress
)
await bobPool.loadDTPool(alicePoolAddress)