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

add complete FixedRate class and basic unit test

This commit is contained in:
lacoop6tu 2021-11-05 14:41:07 -05:00
parent 8f43ae058f
commit 67f19245ef
2 changed files with 461 additions and 9 deletions

View File

@ -791,4 +791,345 @@ export class FixedRateExchange {
return trxReceipt return trxReceipt
} }
/**
* Estimate gas cost for collectBT
* @param {String} account
* @param {String} exchangeId ExchangeId
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estCollectBT(
account: string,
exchangeId: string,
contractInstance?: Contract
): Promise<number> {
const fixedRate = contractInstance || this.fixedRateContract
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await fixedRate.methods
.collectBT(exchangeId)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Collect Basetokens in the contract (only exchange owner)
* @param {String} exchangeId ExchangeId
* @param {String} address User address
* @return {Promise<TransactionReceipt>} transaction receipt
*/
public async collectBT(
address: string,
exchangeId: string
): Promise<TransactionReceipt> {
const exchange = await this.getExchange(exchangeId)
if (!exchange) return null
const estGas = await this.estCollectBT(address, exchangeId)
const trxReceipt = await this.contract.methods.collectBT(exchangeId).send({
from: address,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
return trxReceipt
}
/**
* Estimate gas cost for collecDT
* @param {String} account
* @param {String} exchangeId ExchangeId
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estCollectDT(
account: string,
exchangeId: string,
contractInstance?: Contract
): Promise<number> {
const fixedRate = contractInstance || this.fixedRateContract
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await fixedRate.methods
.collectDT(exchangeId)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Collect datatokens in the contract (only exchange owner)
* @param {String} exchangeId ExchangeId
* @param {String} address User address
* @return {Promise<TransactionReceipt>} transaction receipt
*/
public async collectDT(
address: string,
exchangeId: string
): Promise<TransactionReceipt> {
const exchange = await this.getExchange(exchangeId)
if (!exchange) return null
const estGas = await this.estCollectDT(address, exchangeId)
const trxReceipt = await this.contract.methods.collectDT(exchangeId).send({
from: address,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
return trxReceipt
}
/**
* Estimate gas cost for collecMarketFee
* @param {String} account
* @param {String} exchangeId ExchangeId
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estCollectMarketFee(
account: string,
exchangeId: string,
contractInstance?: Contract
): Promise<number> {
const fixedRate = contractInstance || this.fixedRateContract
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await fixedRate.methods
.collectMarketFee(exchangeId)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Collect market fee and send it to marketFeeCollector (anyone can call it)
* @param {String} exchangeId ExchangeId
* @param {String} address User address
* @return {Promise<TransactionReceipt>} transaction receipt
*/
public async collectMarketFee(
address: string,
exchangeId: string
): Promise<TransactionReceipt> {
const exchange = await this.getExchange(exchangeId)
if (!exchange) return null
const estGas = await this.estCollectMarketFee(address, exchangeId)
const trxReceipt = await this.contract.methods.collectMarketFee(exchangeId).send({
from: address,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
return trxReceipt
}
/**
* Estimate gas cost for collectOceanFee
* @param {String} account
* @param {String} exchangeId ExchangeId
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estCollectOceanFee(
account: string,
exchangeId: string,
contractInstance?: Contract
): Promise<number> {
const fixedRate = contractInstance || this.fixedRateContract
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await fixedRate.methods
.collectMarketFee(exchangeId)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Collect ocean fee and send it to OPF collector (anyone can call it)
* @param {String} exchangeId ExchangeId
* @param {String} address User address
* @return {Promise<TransactionReceipt>} transaction receipt
*/
public async collectOceanFee(
address: string,
exchangeId: string
): Promise<TransactionReceipt> {
const exchange = await this.getExchange(exchangeId)
if (!exchange) return null
const estGas = await this.estCollectOceanFee(address, exchangeId)
const trxReceipt = await this.contract.methods.collectOceanFee(exchangeId).send({
from: address,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
return trxReceipt
}
/**
* Get OPF Collector of fixed rate contract
* @return {String}
*/
async getOPFCollector(): Promise<string> {
let result = null
try {
result = await this.contract.methods.opfCollector().call()
} catch (e) {
this.logger.error(`ERROR: Failed to get OPF Collector address: ${e.message}`)
}
return result
}
/**
* Get Router address set in fixed rate contract
* @return {String}
*/
async getRouter(): Promise<string> {
let result = null
try {
result = await this.contract.methods.router().call()
} catch (e) {
this.logger.error(`ERROR: Failed to get Router address: ${e.message}`)
}
return result
}
/**
* Get Exchange Owner given an exchangeId
* @param {String} exchangeId ExchangeId
* @return {String} return exchange owner
*/
async getExchangeOwner(exchangeId: string): Promise<string> {
let result = null
try {
result = await (await this.getExchange(exchangeId)).exchangeOwner
} catch (e) {
this.logger.error(`ERROR: Failed to get OPF Collector address: ${e.message}`)
}
return result
}
/**
* Estimate gas cost for updateMarketFee
* @param {String} account
* @param {String} exchangeId ExchangeId
* @param {String} newMarketFee New market fee
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estUpdateMarketFee(
account: string,
exchangeId: string,
newMarketFee: string,
contractInstance?: Contract
): Promise<number> {
const fixedRate = contractInstance || this.fixedRateContract
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await fixedRate.methods
.updateMarketFee(exchangeId, newMarketFee)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Set new market fee, only market fee collector can update it
* @param {String} address user address
* @param {String} exchangeId ExchangeId
* @param {String} newMarketFee New market fee
* @return {Promise<TransactionReceipt>} transaction receipt
*/
public async updateMarketFee(
address: string,
exchangeId: string,
newMarketFee: string
): Promise<TransactionReceipt> {
const estGas = await this.estSetRate(
address,
exchangeId,
this.web3.utils.toWei(newMarketFee)
)
const trxReceipt = await this.contract.methods
.updateMarketFee(exchangeId, this.web3.utils.toWei(newMarketFee))
.send({
from: address,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
return trxReceipt
}
/**
* Estimate gas cost for updateMarketFeeCollector
* @param {String} account
* @param {String} exchangeId ExchangeId
* @param {String} newMarketFee New market fee collector
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
public async estUpdateMarketFeeCollector(
account: string,
exchangeId: string,
newMarketFeeCollector: string,
contractInstance?: Contract
): Promise<number> {
const fixedRate = contractInstance || this.fixedRateContract
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try {
estGas = await fixedRate.methods
.updateMarketFeeCollector(exchangeId, newMarketFeeCollector)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
}
return estGas
}
/**
* Set new market fee collector, only market fee collector can update it
* @param {String} address user address
* @param {String} exchangeId ExchangeId
* @param {String} newMarketFeeCollector New market fee collector
* @return {Promise<TransactionReceipt>} transaction receipt
*/
public async updateMarketFeeCollector(
address: string,
exchangeId: string,
newMarketFeeCollector: string
): Promise<TransactionReceipt> {
const estGas = await this.estUpdateMarketFeeCollector(
address,
exchangeId,
newMarketFeeCollector
)
const trxReceipt = await this.contract.methods
.updateMarketFeeCollector(exchangeId, newMarketFeeCollector)
.send({
from: address,
gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3)
})
return trxReceipt
}
} }

View File

@ -31,6 +31,7 @@ describe('Fixed Rate unit test', () => {
let user1: string let user1: string
let user2: string let user2: string
let user3: string let user3: string
let user4: string
let initialBlock: number let initialBlock: number
let fixedRateAddress: string let fixedRateAddress: string
let daiAddress: string let daiAddress: string
@ -74,6 +75,7 @@ describe('Fixed Rate unit test', () => {
user1 = contracts.accounts[2] user1 = contracts.accounts[2]
user2 = contracts.accounts[3] user2 = contracts.accounts[3]
user3 = contracts.accounts[4] user3 = contracts.accounts[4]
user4 = contracts.accounts[5]
exchangeOwner = contracts.accounts[0] exchangeOwner = contracts.accounts[0]
await contracts.deployContracts(factoryOwner, FactoryRouter.abi as AbiItem[]) await contracts.deployContracts(factoryOwner, FactoryRouter.abi as AbiItem[])
@ -154,6 +156,15 @@ describe('Fixed Rate unit test', () => {
expect(await fixedRate.isActive(exchangeId)).to.equal(true) expect(await fixedRate.isActive(exchangeId)).to.equal(true)
expect(await fixedRate.isActive('0x00')).to.equal(false) expect(await fixedRate.isActive('0x00')).to.equal(false)
}) })
it('#getOwner - should get exchange owner given an id', async () => {
expect(await fixedRate.getExchangeOwner(exchangeId)).to.equal(exchangeOwner)
})
it('#getOPFCollector - should get OPF collector', async () => {
expect(await fixedRate.getOPFCollector()).to.equal(contracts.opfCollectorAddress)
})
it('#getRouter - should get Router address', async () => {
expect(await fixedRate.getRouter()).to.equal(contracts.routerAddress)
})
it('#deactivate - should deactivate an exchange if exchangeOwner', async () => { it('#deactivate - should deactivate an exchange if exchangeOwner', async () => {
expect(await fixedRate.isActive(exchangeId)).to.equal(true) expect(await fixedRate.isActive(exchangeId)).to.equal(true)
@ -207,34 +218,44 @@ describe('Fixed Rate unit test', () => {
}) })
it('#getDTSupply - should get the dt supply in the exchange', async () => { it('#getDTSupply - should get the dt supply in the exchange', async () => {
// exchange owner hasn't approved any DT for sell
expect(await fixedRate.getDTSupply(exchangeId)).to.equal('0') expect(await fixedRate.getDTSupply(exchangeId)).to.equal('0')
}) })
it('#getBTSupply - should get the bt supply in the exchange', async () => { it('#getBTSupply - should get the bt supply in the exchange', async () => {
// no basetoken at the beginning
expect(await fixedRate.getBTSupply(exchangeId)).to.equal('0') expect(await fixedRate.getBTSupply(exchangeId)).to.equal('0')
}) })
it('#getBTNeeded - should get bt amount for a specific dt amount', async () => { it('#getAmountBTIn - should get bt amount in for a specific dt amount', async () => {
console.log(await fixedRate.getAmountBTIn(exchangeId, '100')) // 100.2 DAI for 100 DT (0.1% market fee and 0.1% ocean fee)
expect(await fixedRate.getAmountBTIn(exchangeId, '100')).to.equal('100.2')
}) })
it('#getBTNeeded - should get bt amount for a specific dt amount', async () => { it('#getAmountBTOut - should get bt amount out for a specific dt amount', async () => {
console.log(await fixedRate.getAmountBTOut(exchangeId, '100')) // 99.8 DAI for 100 DT (0.1% market fee and 0.1% ocean fee)
expect(await fixedRate.getAmountBTOut(exchangeId, '100')).to.equal('99.8')
}) })
it('#buyDT - user2 should buy some dt', async () => { it('#buyDT - user2 should buy some dt', async () => {
// total supply is ZERO right now so dt owner mints 1000 DT and approves the fixed rate contract
await dtContract.methods await dtContract.methods
.mint(exchangeOwner, web3.utils.toWei('1000')) .mint(exchangeOwner, web3.utils.toWei('1000'))
.send({ from: exchangeOwner }) .send({ from: exchangeOwner })
await dtContract.methods await dtContract.methods
.approve(fixedRateAddress, web3.utils.toWei('1000')) .approve(fixedRateAddress, web3.utils.toWei('1000'))
.send({ from: exchangeOwner }) .send({ from: exchangeOwner })
// user2 gets 100 DAI so he can buy DTs
await daiContract.methods await daiContract.methods
.transfer(user2, web3.utils.toWei('100')) .transfer(user2, web3.utils.toWei('100'))
.send({ from: exchangeOwner }) .send({ from: exchangeOwner })
await daiContract.methods await daiContract.methods
.approve(fixedRateAddress, web3.utils.toWei('100')) .approve(fixedRateAddress, web3.utils.toWei('100'))
.send({ from: user2 }) .send({ from: user2 })
// user2 has no dts but has 100 DAI
expect(await dtContract.methods.balanceOf(user2).call()).to.equal('0') expect(await dtContract.methods.balanceOf(user2).call()).to.equal('0')
const daiBalanceBefore = new BN(await daiContract.methods.balanceOf(user2).call()) const daiBalanceBefore = new BN(await daiContract.methods.balanceOf(user2).call())
expect(daiBalanceBefore.toString()).to.equal(web3.utils.toWei('100')) expect(daiBalanceBefore.toString()).to.equal(web3.utils.toWei('100'))
// user2 buys 10 DT
const tx = await fixedRate.buyDT(user2, exchangeId, '10', '11') const tx = await fixedRate.buyDT(user2, exchangeId, '10', '11')
// console.log(tx.events.Swapped.returnValues) // console.log(tx.events.Swapped.returnValues)
assert(tx.events.Swapped != null) assert(tx.events.Swapped != null)
@ -249,6 +270,10 @@ describe('Fixed Rate unit test', () => {
expect( expect(
daiBalanceBefore.sub(new BN(args.baseTokenSwappedAmount)).toString() daiBalanceBefore.sub(new BN(args.baseTokenSwappedAmount)).toString()
).to.equal(await daiContract.methods.balanceOf(user2).call()) ).to.equal(await daiContract.methods.balanceOf(user2).call())
// basetoken stays in the contract
expect((await fixedRate.getExchange(exchangeId)).btBalance).to.equal('10')
// no dt in the contract
expect((await fixedRate.getExchange(exchangeId)).dtBalance).to.equal('0')
}) })
it('#sellDT - user2 should sell some dt', async () => { it('#sellDT - user2 should sell some dt', async () => {
@ -268,6 +293,12 @@ describe('Fixed Rate unit test', () => {
expect( expect(
daiBalanceBefore.add(new BN(args.baseTokenSwappedAmount)).toString() daiBalanceBefore.add(new BN(args.baseTokenSwappedAmount)).toString()
).to.equal(await daiContract.methods.balanceOf(user2).call()) ).to.equal(await daiContract.methods.balanceOf(user2).call())
// DTs stay in the contract
expect((await fixedRate.getExchange(exchangeId)).dtBalance).to.equal('10')
// no BTs in the contract (except for the fees, but not accounted here)
expect((await fixedRate.getExchange(exchangeId)).btBalance).to.equal('0')
// DT supply is back at 1000 (exchange Owner allowance + dt balance in the fixed rate)
expect(await fixedRate.getDTSupply(exchangeId)).to.equal('1000')
}) })
it('#getExchange - should return exchange details', async () => { it('#getExchange - should return exchange details', async () => {
@ -279,10 +310,10 @@ describe('Fixed Rate unit test', () => {
expect(result.dataToken).to.equal(dtAddress) expect(result.dataToken).to.equal(dtAddress)
expect(result.exchangeOwner).to.equal(exchangeOwner) expect(result.exchangeOwner).to.equal(exchangeOwner)
expect(result.withMint).to.equal(false) expect(result.withMint).to.equal(false)
expect(result.dtBalance).to.equal('10') expect(result.dtBalance).to.equal('10') // balance in the fixedRate
expect(result.btBalance).to.equal('0') expect(result.btBalance).to.equal('0') // balance in the fixedRate
expect(result.dtSupply).to.equal('1000') expect(result.dtSupply).to.equal('1000') // total supply available (owner allowance + dtBalance)
expect(result.btSupply).to.equal('0') expect(result.btSupply).to.equal('0') // total supply available of basetoken in the contract
expect(result.fixedRate).to.equal('1') expect(result.fixedRate).to.equal('1')
}) })
@ -300,9 +331,89 @@ describe('Fixed Rate unit test', () => {
it('#getAllowedSwapper- should return address(0) if not set, if exchangeOwner', async () => { it('#getAllowedSwapper- should return address(0) if not set, if exchangeOwner', async () => {
expect(await fixedRate.getAllowedSwapper(exchangeId)).to.equal(ADDRESS_ZERO) expect(await fixedRate.getAllowedSwapper(exchangeId)).to.equal(ADDRESS_ZERO)
}) })
it('#setAllowedSwapper- should return address(0) if not set, if exchangeOwner', async () => { it('#setAllowedSwapper- should set an allowed swapper, if exchangeOwner', async () => {
await fixedRate.setAllowedSwapper(exchangeOwner, exchangeId, user2) await fixedRate.setAllowedSwapper(exchangeOwner, exchangeId, user2)
expect(await fixedRate.getAllowedSwapper(exchangeId)).to.equal(user2) expect(await fixedRate.getAllowedSwapper(exchangeId)).to.equal(user2)
}) })
it('#setAllowedSwapper- should disable allowed swapper(return address(0)), if exchangeOwner', async () => {
await fixedRate.setAllowedSwapper(exchangeOwner, exchangeId, ADDRESS_ZERO)
expect(await fixedRate.getAllowedSwapper(exchangeId)).to.equal(ADDRESS_ZERO)
})
it('#collectBT- should collect BT in the contract, if exchangeOwner', async () => {
// there are no bt in the contract
expect((await fixedRate.getExchange(exchangeId)).btBalance).to.equal('0')
// user2 buys 1 DT
await fixedRate.buyDT(user2, exchangeId, '1', '2')
// 1 DAI in the contract
expect((await fixedRate.getExchange(exchangeId)).btBalance).to.equal('1')
// owner collects BTs
await fixedRate.collectBT(exchangeOwner, exchangeId)
// btBalance is zero
expect((await fixedRate.getExchange(exchangeId)).btBalance).to.equal('0')
})
it('#collectDT- should collect DT in the contract, if exchangeOwner', async () => {
const result = await fixedRate.getExchange(exchangeId)
// 9 dts left
expect(result.dtBalance).to.equal('9')
// owner collects DTs
await fixedRate.collectDT(exchangeOwner, exchangeId)
// no more dts in the contract
const result2 = await fixedRate.getExchange(exchangeId)
expect(result2.dtBalance).to.equal('0')
// Only allowance left since dt is ZERO
expect(result2.dtSupply).to.equal('990')
})
it('#collectMarketFee- should collect marketFee and send it to marketFeeCollector, anyone can call it', async () => {
let result = await fixedRate.getFeesInfo(exchangeId)
// we made 2 swaps for 10 DT at rate 1, the fee is 0.1% for market and always in basetoken so it's 0.01 DAI
// plus another swap for 1 DT
expect(result.marketFeeAvailable).to.equal('0.021') // formatted for basetoken decimals
// same for ocean fee
expect(result.oceanFeeAvailable).to.equal('0.021') // formatted for basetoken decimals
expect(result.marketFeeCollector).to.equal(user3)
// user4 calls collectMarketFee
await fixedRate.collectMarketFee(user4, exchangeId)
result = await fixedRate.getFeesInfo(exchangeId)
expect(result.marketFeeAvailable).to.equal('0')
// ocean fee still available
expect(result.oceanFeeAvailable).to.equal('0.021')
// user3 is the marketFeeCollector
expect(await daiContract.methods.balanceOf(user3).call()).to.equal(
web3.utils.toWei('0.021')
)
})
it('#collectOceanFee- should collect oceanFee and send it to OPF Collector, anyone can call it', async () => {
let result = await fixedRate.getFeesInfo(exchangeId)
// we made 2 swaps for 10 DT at rate 1, the fee is 0.1% for market and always in basetoken so it's 0.01 DAI
// plus another swap for 1 DT
expect(result.oceanFeeAvailable).to.equal('0.021') // formatted for basetoken decimals
// user4 calls collectOceanFee
await fixedRate.collectOceanFee(user4, exchangeId)
result = await fixedRate.getFeesInfo(exchangeId)
// fee has been reset
expect(result.oceanFeeAvailable).to.equal('0')
// OPF collector got the fee
expect(
await daiContract.methods.balanceOf(await fixedRate.getOPFCollector()).call()
).to.equal(web3.utils.toWei('0.021'))
})
it('#updateMarketFee- should update Market fee if market fee collector', async () => {
expect((await fixedRate.getFeesInfo(exchangeId)).marketFee).to.equal('0.001')
// user3 is marketFeeCollector
await fixedRate.updateMarketFee(user3, exchangeId, '0.01')
expect((await fixedRate.getFeesInfo(exchangeId)).marketFee).to.equal('0.01')
})
it('#updateMarketFeeCollector - should update Market fee collector if market fee collector', async () => {
expect((await fixedRate.getFeesInfo(exchangeId)).marketFeeCollector).to.equal(user3)
await fixedRate.updateMarketFeeCollector(user3, exchangeId, user2)
expect((await fixedRate.getFeesInfo(exchangeId)).marketFeeCollector).to.equal(user2)
})
}) })
}) })