From 4468967d07824f4bb9eb5d5a6e13c2f0fd7be274 Mon Sep 17 00:00:00 2001 From: surangap Date: Mon, 28 Mar 2022 19:19:45 +0800 Subject: [PATCH 01/32] Added dfip2203 futures rpcs. --- docs/node/CATEGORIES/08-account.md | 79 +++++++++++++++++++ docs/node/CATEGORIES/09-oracle.md | 10 +++ .../src/category/account.ts | 67 ++++++++++++++++ .../jellyfish-api-core/src/category/oracle.ts | 9 +++ 4 files changed, 165 insertions(+) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index 87d6bfcca4..d170e5daba 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -466,3 +466,82 @@ interface BurnInfo { paybacktokens: string[] } ``` + +## futureSwap + +Creates and submits to the network a futures contract. + +```ts title="client.account.futureSwap()" +interface account { + futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise +} + +interface FutureSwap { + address: string + amount: string + destination: number +} + +interface UTXO { + txid: string + vout: number +} +``` + +## withdrawFutureSwap + +Creates and submits to the network a withdrawl from futures contract transaction. + +```ts title="client.account.withdrawFutureSwap()" +interface account { + withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise +} + +interface FutureSwap { + address: string + amount: string + destination: number +} + +interface UTXO { + txid: string + vout: number +} +``` + +## listPendingFutureSwaps + +List all pending futures. + +```ts title="client.account.listPendingFutureSwaps()" +interface account { + listPendingFutureSwaps (): Promise +} + +interface FutureInfo { + owner: string + source: string + destination: string +} +``` + +## getPendingFutureSwaps + +Get specific pending futures. + +```ts title="client.account.getPendingFutureSwaps()" +interface account { + getPendingFutureSwaps (): Promise +} + +interface GetFutureInfo { + owner: string + values: Omit [] +} + +interface FutureInfo { + owner: string + source: string + destination: string +} +``` diff --git a/docs/node/CATEGORIES/09-oracle.md b/docs/node/CATEGORIES/09-oracle.md index 4754a33c41..7f6c49f7aa 100644 --- a/docs/node/CATEGORIES/09-oracle.md +++ b/docs/node/CATEGORIES/09-oracle.md @@ -250,3 +250,13 @@ interface ListFixedIntervalPrice { isLive: boolean } ``` + +## getFutureSwapBlock + +Get the next block that futures will execute and update on. + +```ts title="client.oracle.getFutureSwapBlock()" +interface oracle { + getFutureSwapBlock (): Promise +} +``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 039a3fe5b9..8f3ca19c30 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -388,6 +388,56 @@ export class Account { async getBurnInfo (): Promise { return await this.client.call('getburninfo', [], 'bignumber') } + + /** + * Creates and submits to the network a futures contract. + * + * @param {FutureSwap} future + * @param {string} future.address Address to fund contract and receive resulting token + * @param {string} future.amount Amount to send in amount@token format + * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {UTXO[]} [options.utxos = []] + * @param {string} options.utxos.txid + * @param {number} options.utxos.vout + * @return {Promise} + */ + async futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { + return await this.client.call('futureswap', [future, utxos], 'number') + } + + /** + * Creates and submits to the network a withdrawl from futures contract transaction. + * + * @param {FutureSwap} future + * @param {string} future.address Address to fund contract and receive resulting token + * @param {string} future.amount Amount to send in amount@token format + * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {UTXO[]} [options.utxos = []] + * @param {string} options.utxos.txid + * @param {number} options.utxos.vout + * @return {Promise} + */ + async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { + return await this.client.call('withdrawfutureswap', [future, utxos], 'number') + } + + /** + * List all pending futures. + * + * @return {Promise} + */ + async listPendingFutureSwaps (): Promise { + return await this.client.call('listpendingfutureswaps', [], 'number') + } + + /** + * Get specific pending futures. + * + * @return {Promise} + */ + async getPendingFutureSwaps (): Promise { + return await this.client.call('getpendingfutureswaps', [], 'number') + } } export interface AccountPagination { @@ -552,3 +602,20 @@ export interface BurnInfo { */ paybacktokens: string[] } + +export interface FutureSwap { + address: string + amount: string + destination: number +} + +export interface FutureInfo { + owner: string + source: string + destination: string +} + +export interface GetFutureInfo { + owner: string + values: Array> +} diff --git a/packages/jellyfish-api-core/src/category/oracle.ts b/packages/jellyfish-api-core/src/category/oracle.ts index be7cd24380..940c2f155b 100644 --- a/packages/jellyfish-api-core/src/category/oracle.ts +++ b/packages/jellyfish-api-core/src/category/oracle.ts @@ -160,6 +160,15 @@ export class Oracle { nextPrice: 'bignumber' }) } + + /** + * Get the next block that futures will execute and update on. + * + * @return {Promise} + */ + async getFutureSwapBlock (): Promise { + return await this.client.call('getfutureswapblock', [], 'number') + } } export interface AppointOracleOptions { From 68f69fa86dfd5ee069d29330d3f6ddb26d9f07a5 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 29 Mar 2022 15:17:15 +0800 Subject: [PATCH 02/32] Added listFutureSwapHistory rpc. --- docs/node/CATEGORIES/08-account.md | 29 +++++++++++++++++++ .../src/category/account.ts | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index d170e5daba..ae12b647bd 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -545,3 +545,32 @@ interface FutureInfo { destination: string } ``` + +## listFutureSwapHistory + +Returns information about future swap history. + +```ts title="client.account.listFutureSwapHistory()" +interface account { + listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise +} + +enum OwnerType { + MINE = 'mine', + ALL = 'all' +} + +interface ListFutureHistoryOptions { + maxBlockHeight: number + depth: number + token: string + limit: number +} + +interface FutureHistory { + height: number + address: string + source: string + destination: string +} +``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 8f3ca19c30..28d1abfa80 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -438,6 +438,21 @@ export class Account { async getPendingFutureSwaps (): Promise { return await this.client.call('getpendingfutureswaps', [], 'number') } + + /** + * Returns information about future swap history. + * + * @param {OwnerType | string} [owner=OwnerType.MINE] single account ID (CScript or address) or reserved words 'mine' to list history for all owned accounts or 'all' to list whole DB + * @param {ListFutureHistoryOptions} [options] + * @param {number} [options.maxBlockHeight] Optional height to iterate from (downto genesis block), (default = chaintip). + * @param {number} [options.depth] Maximum depth, from the genesis block is the default + * @param {string} [options.token] Filter by token + * @param {number} [options.limit=100] Maximum number of records to return, 100 by default + * @return {Promise} + */ + async listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise { + return await this.client.call('listfutureswaphistory', [], 'number') + } } export interface AccountPagination { @@ -619,3 +634,17 @@ export interface GetFutureInfo { owner: string values: Array> } + +export interface ListFutureHistoryOptions { + maxBlockHeight: number + depth: number + token: string + limit: number +} + +export interface FutureHistory { + height: number + address: string + source: string + destination: string +} From a13362419f3b8b786d7f4282623899b93eba5c36 Mon Sep 17 00:00:00 2001 From: surangap Date: Fri, 1 Apr 2022 15:09:40 +0800 Subject: [PATCH 03/32] Updated futureswap API. --- docs/node/CATEGORIES/08-account.md | 33 ++----------------- .../src/category/account.ts | 21 ++---------- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index ae12b647bd..d9be7b91f5 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -479,7 +479,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: number + destination: string } interface UTXO { @@ -500,7 +500,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: number + destination: string } interface UTXO { @@ -544,33 +544,4 @@ interface FutureInfo { source: string destination: string } -``` - -## listFutureSwapHistory - -Returns information about future swap history. - -```ts title="client.account.listFutureSwapHistory()" -interface account { - listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise -} - -enum OwnerType { - MINE = 'mine', - ALL = 'all' -} - -interface ListFutureHistoryOptions { - maxBlockHeight: number - depth: number - token: string - limit: number -} - -interface FutureHistory { - height: number - address: string - source: string - destination: string -} ``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 28d1abfa80..ab5bcb2074 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -395,7 +395,7 @@ export class Account { * @param {FutureSwap} future * @param {string} future.address Address to fund contract and receive resulting token * @param {string} future.amount Amount to send in amount@token format - * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {string} [future.destination] Expected dToken if DUSD supplied * @param {UTXO[]} [options.utxos = []] * @param {string} options.utxos.txid * @param {number} options.utxos.vout @@ -411,7 +411,7 @@ export class Account { * @param {FutureSwap} future * @param {string} future.address Address to fund contract and receive resulting token * @param {string} future.amount Amount to send in amount@token format - * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {string} [future.destination] Expected dToken if DUSD supplied * @param {UTXO[]} [options.utxos = []] * @param {string} options.utxos.txid * @param {number} options.utxos.vout @@ -438,21 +438,6 @@ export class Account { async getPendingFutureSwaps (): Promise { return await this.client.call('getpendingfutureswaps', [], 'number') } - - /** - * Returns information about future swap history. - * - * @param {OwnerType | string} [owner=OwnerType.MINE] single account ID (CScript or address) or reserved words 'mine' to list history for all owned accounts or 'all' to list whole DB - * @param {ListFutureHistoryOptions} [options] - * @param {number} [options.maxBlockHeight] Optional height to iterate from (downto genesis block), (default = chaintip). - * @param {number} [options.depth] Maximum depth, from the genesis block is the default - * @param {string} [options.token] Filter by token - * @param {number} [options.limit=100] Maximum number of records to return, 100 by default - * @return {Promise} - */ - async listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise { - return await this.client.call('listfutureswaphistory', [], 'number') - } } export interface AccountPagination { @@ -621,7 +606,7 @@ export interface BurnInfo { export interface FutureSwap { address: string amount: string - destination: number + destination: string } export interface FutureInfo { From a9990a2f63a117ca460be7dcd5ee0bcc6e81d8de Mon Sep 17 00:00:00 2001 From: surangap Date: Sun, 3 Apr 2022 21:43:43 +0800 Subject: [PATCH 04/32] Added futureswap tests. --- docs/node/CATEGORIES/08-account.md | 8 +- .../category/account/futureswap.test.ts | 332 ++++++++++++++++++ .../src/category/account.ts | 8 +- packages/jellyfish-testing/src/token.ts | 5 + .../src/containers/DeFiDContainer.ts | 2 +- 5 files changed, 350 insertions(+), 5 deletions(-) create mode 100644 packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index d9be7b91f5..ab7b617fcb 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -464,6 +464,10 @@ interface BurnInfo { * Amount of tokens that are paid back */ paybacktokens: string[] + /** + * Amount of tokens burned due to futureswap + */ + dfip2203: string[] } ``` @@ -479,7 +483,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: string + destination?: string } interface UTXO { @@ -500,7 +504,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: string + destination?: string } interface UTXO { diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts new file mode 100644 index 0000000000..dc551e8fc2 --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -0,0 +1,332 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import BigNumber from 'bignumber.js' +import { Testing } from '@defichain/jellyfish-testing' +import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' + +const container = new MasterNodeRegTestContainer() +const testing = Testing.create(container) +let collateralAddress: string +let oracleId: string +let idDUSD: string +let idTSLA: string +// let idAMZN: string +// let idBTC: string +const attributeKey = 'ATTRIBUTES' +// let key: string +let futInterval: number +let futRewardPercentage: number +const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' + +async function setup (): Promise { + collateralAddress = await testing.generateAddress() + await testing.token.dfi({ address: collateralAddress, amount: 300000 }) + await testing.token.create({ symbol: 'BTC', collateralAddress }) + await testing.generate(1) + await testing.token.mint({ symbol: 'BTC', amount: 20000 }) + await testing.generate(1) + + // loan scheme + await testing.container.call('createloanscheme', [100, 1, 'default']) + await testing.generate(1) + + // price oracle + const priceFeeds = [ + { token: 'DFI', currency: 'USD' }, + { token: 'BTC', currency: 'USD' }, + { token: 'TSLA', currency: 'USD' }, + { token: 'AMZN', currency: 'USD' }, + { token: 'DUSD', currency: 'USD' } + ] + + const addr = await testing.generateAddress() + oracleId = await testing.rpc.oracle.appointOracle(addr, priceFeeds, { weightage: 1 }) + await testing.generate(1) + + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '1@DFI', currency: 'USD' }, + { tokenAmount: '10000@BTC', currency: 'USD' }, + { tokenAmount: '2@TSLA', currency: 'USD' }, + { tokenAmount: '4@AMZN', currency: 'USD' }, + { tokenAmount: '1@DUSD', currency: 'USD' } + ] + } + ) + await testing.generate(1) + + // collateral tokens + await testing.rpc.loan.setCollateralToken({ + token: 'DFI', + factor: new BigNumber(1), + fixedIntervalPriceId: 'DFI/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setCollateralToken({ + token: 'BTC', + factor: new BigNumber(0.5), + fixedIntervalPriceId: 'BTC/USD' + }) + await testing.generate(1) + + // loan token + await testing.rpc.loan.setLoanToken({ + symbol: 'TSLA', + fixedIntervalPriceId: 'TSLA/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setLoanToken({ + symbol: 'AMZN', + fixedIntervalPriceId: 'AMZN/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setLoanToken({ + symbol: 'DUSD', + fixedIntervalPriceId: 'DUSD/USD' + }) + await testing.generate(1) + + // idBTC = await testing.token.getTokenId('BTC') + idTSLA = await testing.token.getTokenId('TSLA') + // idAMZN = await testing.token.getTokenId('AMZN') + idDUSD = await testing.token.getTokenId('DUSD') + + // create a vault and take loans + const vaultAddr = await testing.generateAddress() + const vaultId = await testing.rpc.loan.createVault({ + ownerAddress: vaultAddr, + loanSchemeId: 'default' + }) + await testing.generate(1) + + await testing.rpc.loan.depositToVault({ + vaultId: vaultId, from: collateralAddress, amount: '100000@DFI' + }) + + // wait till the price valid. + await testing.container.waitForPriceValid('TSLA/USD') + + // take multiple loans + await testing.rpc.loan.takeLoan({ + vaultId: vaultId, + to: collateralAddress, + amounts: ['300@TSLA', '500@DUSD', '100@AMZN'] + }) + await testing.generate(1) + + // Futures setup + // set the dfip2203/active to false + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + + // set dfip2203 params + futInterval = 25 + futRewardPercentage = 0.05 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': futRewardPercentage.toString(), 'v0/params/dfip2203/block_period': futInterval.toString() } }) + await testing.generate(1) + + // activat the dfip2203/active now + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) + await testing.generate(1) + + // Retrive and verify gov vars + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('true') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(futRewardPercentage.toString()) + expect(attributes.ATTRIBUTES['v0/params/dfip2203/block_period']).toStrictEqual(futInterval.toString()) +} + +async function getNextSettleBlock (): Promise { + const blockCount = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = blockCount + (futInterval - (blockCount % futInterval)) + return nextSettleBlock +} + +describe('futureSwap', () => { + beforeEach(async () => { + await testing.container.start() + await testing.container.waitForWalletCoinbaseMaturity() + await setup() + }) + + afterEach(async () => { + await testing.container.stop() + }) + + it('should create futureswap dtoken to dusd', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@TSLA') + expect(pendingFutures[0].destination).toStrictEqual('DUSD') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([]) + } + } + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // move to next settle block + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + // check future settled + { + // calclulate minted DUSD. dtoken goes for a discount. + const mintedDUSD = (1 - futRewardPercentage) * 2 * swapAmount // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + }) + + it('should create futureswap dusd to dtoken', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([]) + } + } + + // get minted TSLA + const tslaMintedBefore = (await testing.rpc.token.getToken(idTSLA))[idTSLA].minted + + // move to next settle block + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + // check future settled + { + // calclulate minted TSLA. dtoken goes for a premium. + const mintedTSLA = new BigNumber((1 / (1 + futRewardPercentage)) * (1 / 2) * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1/(1 + reward percentage)) * (DUSDTSLA) value * DUSD swap amount; + const tslaMintedAfter = (await testing.rpc.token.getToken(idTSLA))[idTSLA].minted + expect(tslaMintedAfter).toStrictEqual(tslaMintedBefore.plus(mintedTSLA)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedTSLA.toString() + '@TSLA']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedTSLA.toString() + '@TSLA']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + }) +}) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index ab5bcb2074..41cb2e7f3f 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -402,7 +402,7 @@ export class Account { * @return {Promise} */ async futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('futureswap', [future, utxos], 'number') + return await this.client.call('futureswap', [future.address, future.amount, future.destination, utxos], 'number') } /** @@ -601,12 +601,16 @@ export interface BurnInfo { * Amount of tokens that are paid back */ paybacktokens: string[] + /** + * Amount of tokens burned due to futureswap + */ + dfip2203: string[] } export interface FutureSwap { address: string amount: string - destination: string + destination?: string } export interface FutureInfo { diff --git a/packages/jellyfish-testing/src/token.ts b/packages/jellyfish-testing/src/token.ts index 76807f678b..1a17fd84a7 100644 --- a/packages/jellyfish-testing/src/token.ts +++ b/packages/jellyfish-testing/src/token.ts @@ -43,6 +43,11 @@ export class TestingToken { const to = { [address]: [account] } return await this.rpc.account.sendTokensToAddress({}, to) } + + async getTokenId (symbol: string): Promise { + const tokenInfo = await this.rpc.token.getToken(symbol) + return Object.keys(tokenInfo)[0] + } } interface TestingTokenCreate { diff --git a/packages/testcontainers/src/containers/DeFiDContainer.ts b/packages/testcontainers/src/containers/DeFiDContainer.ts index f6e7402e24..d922137df4 100644 --- a/packages/testcontainers/src/containers/DeFiDContainer.ts +++ b/packages/testcontainers/src/containers/DeFiDContainer.ts @@ -35,7 +35,7 @@ export abstract class DeFiDContainer extends DockerContainer { if (process?.env?.DEFICHAIN_DOCKER_IMAGE !== undefined) { return process.env.DEFICHAIN_DOCKER_IMAGE } - return 'defi/defichain:master-2a236bb79' + return 'defi/defichain:master-35ad71b82' } public static readonly DefaultStartOptions = { From fa1ca7dbeee639fc4fa85eb8567f340b448047c9 Mon Sep 17 00:00:00 2001 From: surangap Date: Mon, 4 Apr 2022 19:02:09 +0800 Subject: [PATCH 05/32] Updated tests. --- .../category/account/futureswap.test.ts | 399 +++++++++++++++++- .../containers/RegTestContainer/Masternode.ts | 24 ++ 2 files changed, 422 insertions(+), 1 deletion(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index dc551e8fc2..33731026d2 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -2,6 +2,7 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import BigNumber from 'bignumber.js' import { Testing } from '@defichain/jellyfish-testing' import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' +import { RpcApiError } from '@defichain/jellyfish-api-core' const container = new MasterNodeRegTestContainer() const testing = Testing.create(container) @@ -213,7 +214,7 @@ describe('futureSwap', () => { // check future settled { // calclulate minted DUSD. dtoken goes for a discount. - const mintedDUSD = (1 - futRewardPercentage) * 2 * swapAmount // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) @@ -244,6 +245,232 @@ describe('futureSwap', () => { expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) }) + it('should create futureswap dtoken to dusd just before the next settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // move to next settle block - 1 + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount() - 1) + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check future settled + { + // calclulate minted DUSD. dtoken goes for a discount. + const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + }) + + it('should consider new oracle active price, if changed before futureswap execution', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + let blockHeight = await testing.rpc.blockchain.getBlockCount() + let nextSettleBlock = await getNextSettleBlock() + + // move to next settle block for better duration for the oracle price to kick in + await testing.generate(nextSettleBlock - blockHeight) + blockHeight = await testing.rpc.blockchain.getBlockCount() + nextSettleBlock = await getNextSettleBlock() + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // change the oracle price + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '2.2@TSLA', currency: 'USD' } + ] + } + ) + await testing.generate(1) + await testing.container.waitForActivePrice('TSLA/USD', '2.2') + + const blockHeightAfter = await testing.rpc.blockchain.getBlockCount() + + // check next settle block is not reached yet + expect(blockHeightAfter).toBeLessThan(nextSettleBlock) + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // move to nextSettleBlock + await testing.generate(nextSettleBlock - blockHeightAfter) + + // check future settled + { + // calclulate minted DUSD. dtoken goes for a discount. + const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2.2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + }) + + it('should refund if the oracle price is invalid at futureswap execution block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + let blockHeight = await testing.rpc.blockchain.getBlockCount() + let nextSettleBlock = await getNextSettleBlock() + + // move to next settle block + await testing.generate(nextSettleBlock - blockHeight) + blockHeight = await testing.rpc.blockchain.getBlockCount() + nextSettleBlock = await getNextSettleBlock() + const nextPriceBlock = await testing.container.getImmediatePriceBlockBeforeBlock('TSLA/USD', nextSettleBlock) + + // create the futureswap + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the futureswap is in effect + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + + // move to nextPriceBlock - 1 + await testing.generate(nextPriceBlock - 1 - await testing.rpc.blockchain.getBlockCount()) + + // change the oracle price + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '3@TSLA', currency: 'USD' } + ] + } + ) + await testing.generate(1) + { + // now check the price invalid + const priceDataInvalid = await testing.rpc.oracle.getFixedIntervalPrice('TSLA/USD') + expect(priceDataInvalid.isLive).toBeFalsy() + } + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // move to nextSettleBlock + await testing.generate(nextSettleBlock - nextPriceBlock) + + // check price is still invalid + { + const priceDataInvalid = await testing.rpc.oracle.getFixedIntervalPrice('TSLA/USD') + expect(priceDataInvalid.isLive).toBeFalsy() + } + + // check futureswap is not executed. + { + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([]) + }) + it('should create futureswap dusd to dtoken', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) @@ -329,4 +556,174 @@ describe('futureSwap', () => { const burnAfter = await testing.rpc.account.getBurnInfo() expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) }) + + it('should not create futureswap when DFIP2203 is not active', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // deactivate DFIP2203 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('false') + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + + const promise = testing.rpc.account.futureSwap(fswap) + + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDFIP2203 not currently active\', code: -32600, method: futureswap') + }) + + it('should refund the futureswap if DFIP2203 is disabled before execution', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // create the futureswap + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const nextSettleBlock = await getNextSettleBlock() + + // check the futureswap is in effect + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // deactivate DFIP2203 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('false') + + // move to nextSettleBlock + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + // check futureswap is not executed. + { + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([]) + }) + + it('should not create futureswap when invalid inputs given', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + { + // zero source amount is given + const fswap: FutureSwap = { + address: tslaAddress, + amount: '0@TSLA' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: futureswap') + } + { + // negative source amount is given + const fswap: FutureSwap = { + address: tslaAddress, + amount: '-1@TSLA' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: futureswap') + } + { + // invlaid source dtoken + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@INVALID' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: futureswap') + } + { + // destination is given when futureswap dtoken to dusd + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@TSLA', + destination: 'DUSD' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDestination should not be set when source amount is a dToken\', code: -32600, method: futureswap') + } + { + // INVALID destination is given when futureswap dusd to dtoken + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@DUSD', + destination: 'INVALID' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Destination token not found\', code: -5, method: futureswap') + } + }) + + it('should not create futureswap when DFIP2203 is disabled for the dtoken', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // deactivate DFIP2203 for dtoken + const key = 'v0/token/' + idTSLA + '/dfip2203' + + await testing.rpc.masternode.setGov({ [attributeKey]: { [key]: 'false' } }) + await testing.generate(1) + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES[key]).toStrictEqual('false') + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDFIP2203 currently disabled for token 2\', code: -32600, method: futureswap') + }) }) diff --git a/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts b/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts index 78d71b6d03..1a5f4dc2ec 100644 --- a/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts +++ b/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts @@ -239,6 +239,14 @@ export class MasterNodeRegTestContainer extends RegTestContainer { }, timeout, 100, 'waitForPriceInvalid') } + /** + * Wait for valut state + * + * @param {string} vaultId + * @param {string} state + * @param {number} [timeout=30000] in ms + * @return {Promise} + */ async waitForVaultState (vaultId: string, state: string, timeout = 30000): Promise { return await waitForCondition(async () => { const vault = await this.call('getvault', [vaultId]) @@ -250,6 +258,22 @@ export class MasterNodeRegTestContainer extends RegTestContainer { }, timeout, 100, 'waitForVaultState') } + /** + * Get next price block before the given target block + * + * @param {string} fixedIntervalPriceId + * @param {number} [targetBlock] + * @return {Promise} + */ + async getImmediatePriceBlockBeforeBlock (fixedIntervalPriceId: string, targetBlock: number): Promise { + const data: any = await this.call('getfixedintervalprice', [fixedIntervalPriceId]) + let nextPriceBlock = data.nextPriceBlock as number + while (nextPriceBlock < targetBlock) { + nextPriceBlock += 6 // 1 hour in regtest is 6 blocks + } + return nextPriceBlock + } + /** * Wait for active price * From 4d137e24a06aaaa501b751afd6cb8af2ae274c24 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Tue, 5 Apr 2022 09:11:14 +0530 Subject: [PATCH 06/32] Addted a test to withdraw fututre swap --- .../category/account/futureswap.test.ts | 58 +++++++++++++++++++ .../src/category/account.ts | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index 33731026d2..945e8849d7 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -557,6 +557,64 @@ describe('futureSwap', () => { expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) }) + it('should withdraw futureswap', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + } + + const withdraw = 0.5 + const fswapWithdraw: FutureSwap = { + address: tslaAddress, + amount: withdraw.toString() + '@DUSD', + destination: 'TSLA' + } + + // Withdraw half of future swap + { + await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) + await testing.generate(1) + } + + // check the future after withdraw half + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdraw).toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + } + + // Withdraw second half of future swap + { + await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) + await testing.generate(1) + } + + // check the future after withdrawing all + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + } + }) + it('should not create futureswap when DFIP2203 is not active', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 41cb2e7f3f..cf928298b9 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -418,7 +418,7 @@ export class Account { * @return {Promise} */ async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('withdrawfutureswap', [future, utxos], 'number') + return await this.client.call('withdrawfutureswap', [future.address, future.amount, future.destination, utxos], 'number') } /** From 6999c86e84e77768cfbb020e39489f086dac3a90 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Tue, 5 Apr 2022 09:30:37 +0530 Subject: [PATCH 07/32] Revert "Addted a test to withdraw fututre swap" This reverts commit 4d137e24a06aaaa501b751afd6cb8af2ae274c24. --- .../category/account/futureswap.test.ts | 58 ------------------- .../src/category/account.ts | 2 +- 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index 945e8849d7..33731026d2 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -557,64 +557,6 @@ describe('futureSwap', () => { expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) }) - it('should withdraw futureswap', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) - await testing.generate(1) - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', - destination: 'TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') - expect(pendingFutures[0].destination).toStrictEqual('TSLA') - } - - const withdraw = 0.5 - const fswapWithdraw: FutureSwap = { - address: tslaAddress, - amount: withdraw.toString() + '@DUSD', - destination: 'TSLA' - } - - // Withdraw half of future swap - { - await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) - await testing.generate(1) - } - - // check the future after withdraw half - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdraw).toFixed(8) + '@DUSD') - expect(pendingFutures[0].destination).toStrictEqual('TSLA') - } - - // Withdraw second half of future swap - { - await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) - await testing.generate(1) - } - - // check the future after withdrawing all - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - } - }) - it('should not create futureswap when DFIP2203 is not active', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index cf928298b9..41cb2e7f3f 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -418,7 +418,7 @@ export class Account { * @return {Promise} */ async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('withdrawfutureswap', [future.address, future.amount, future.destination, utxos], 'number') + return await this.client.call('withdrawfutureswap', [future, utxos], 'number') } /** From 020780113db8bc4bfa20caf640f4fb0636eddf5c Mon Sep 17 00:00:00 2001 From: surangap Date: Mon, 28 Mar 2022 19:19:45 +0800 Subject: [PATCH 08/32] Added dfip2203 futures rpcs. --- docs/node/CATEGORIES/08-account.md | 79 +++++++++++++++++++ docs/node/CATEGORIES/09-oracle.md | 10 +++ .../src/category/account.ts | 67 ++++++++++++++++ .../jellyfish-api-core/src/category/oracle.ts | 9 +++ 4 files changed, 165 insertions(+) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index 87d6bfcca4..d170e5daba 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -466,3 +466,82 @@ interface BurnInfo { paybacktokens: string[] } ``` + +## futureSwap + +Creates and submits to the network a futures contract. + +```ts title="client.account.futureSwap()" +interface account { + futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise +} + +interface FutureSwap { + address: string + amount: string + destination: number +} + +interface UTXO { + txid: string + vout: number +} +``` + +## withdrawFutureSwap + +Creates and submits to the network a withdrawl from futures contract transaction. + +```ts title="client.account.withdrawFutureSwap()" +interface account { + withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise +} + +interface FutureSwap { + address: string + amount: string + destination: number +} + +interface UTXO { + txid: string + vout: number +} +``` + +## listPendingFutureSwaps + +List all pending futures. + +```ts title="client.account.listPendingFutureSwaps()" +interface account { + listPendingFutureSwaps (): Promise +} + +interface FutureInfo { + owner: string + source: string + destination: string +} +``` + +## getPendingFutureSwaps + +Get specific pending futures. + +```ts title="client.account.getPendingFutureSwaps()" +interface account { + getPendingFutureSwaps (): Promise +} + +interface GetFutureInfo { + owner: string + values: Omit [] +} + +interface FutureInfo { + owner: string + source: string + destination: string +} +``` diff --git a/docs/node/CATEGORIES/09-oracle.md b/docs/node/CATEGORIES/09-oracle.md index 4754a33c41..7f6c49f7aa 100644 --- a/docs/node/CATEGORIES/09-oracle.md +++ b/docs/node/CATEGORIES/09-oracle.md @@ -250,3 +250,13 @@ interface ListFixedIntervalPrice { isLive: boolean } ``` + +## getFutureSwapBlock + +Get the next block that futures will execute and update on. + +```ts title="client.oracle.getFutureSwapBlock()" +interface oracle { + getFutureSwapBlock (): Promise +} +``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 039a3fe5b9..8f3ca19c30 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -388,6 +388,56 @@ export class Account { async getBurnInfo (): Promise { return await this.client.call('getburninfo', [], 'bignumber') } + + /** + * Creates and submits to the network a futures contract. + * + * @param {FutureSwap} future + * @param {string} future.address Address to fund contract and receive resulting token + * @param {string} future.amount Amount to send in amount@token format + * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {UTXO[]} [options.utxos = []] + * @param {string} options.utxos.txid + * @param {number} options.utxos.vout + * @return {Promise} + */ + async futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { + return await this.client.call('futureswap', [future, utxos], 'number') + } + + /** + * Creates and submits to the network a withdrawl from futures contract transaction. + * + * @param {FutureSwap} future + * @param {string} future.address Address to fund contract and receive resulting token + * @param {string} future.amount Amount to send in amount@token format + * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {UTXO[]} [options.utxos = []] + * @param {string} options.utxos.txid + * @param {number} options.utxos.vout + * @return {Promise} + */ + async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { + return await this.client.call('withdrawfutureswap', [future, utxos], 'number') + } + + /** + * List all pending futures. + * + * @return {Promise} + */ + async listPendingFutureSwaps (): Promise { + return await this.client.call('listpendingfutureswaps', [], 'number') + } + + /** + * Get specific pending futures. + * + * @return {Promise} + */ + async getPendingFutureSwaps (): Promise { + return await this.client.call('getpendingfutureswaps', [], 'number') + } } export interface AccountPagination { @@ -552,3 +602,20 @@ export interface BurnInfo { */ paybacktokens: string[] } + +export interface FutureSwap { + address: string + amount: string + destination: number +} + +export interface FutureInfo { + owner: string + source: string + destination: string +} + +export interface GetFutureInfo { + owner: string + values: Array> +} diff --git a/packages/jellyfish-api-core/src/category/oracle.ts b/packages/jellyfish-api-core/src/category/oracle.ts index be7cd24380..940c2f155b 100644 --- a/packages/jellyfish-api-core/src/category/oracle.ts +++ b/packages/jellyfish-api-core/src/category/oracle.ts @@ -160,6 +160,15 @@ export class Oracle { nextPrice: 'bignumber' }) } + + /** + * Get the next block that futures will execute and update on. + * + * @return {Promise} + */ + async getFutureSwapBlock (): Promise { + return await this.client.call('getfutureswapblock', [], 'number') + } } export interface AppointOracleOptions { From 2320d9903535ff2bef56908772b7c17b953a7c3e Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 29 Mar 2022 15:17:15 +0800 Subject: [PATCH 09/32] Added listFutureSwapHistory rpc. --- docs/node/CATEGORIES/08-account.md | 29 +++++++++++++++++++ .../src/category/account.ts | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index d170e5daba..ae12b647bd 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -545,3 +545,32 @@ interface FutureInfo { destination: string } ``` + +## listFutureSwapHistory + +Returns information about future swap history. + +```ts title="client.account.listFutureSwapHistory()" +interface account { + listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise +} + +enum OwnerType { + MINE = 'mine', + ALL = 'all' +} + +interface ListFutureHistoryOptions { + maxBlockHeight: number + depth: number + token: string + limit: number +} + +interface FutureHistory { + height: number + address: string + source: string + destination: string +} +``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 8f3ca19c30..28d1abfa80 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -438,6 +438,21 @@ export class Account { async getPendingFutureSwaps (): Promise { return await this.client.call('getpendingfutureswaps', [], 'number') } + + /** + * Returns information about future swap history. + * + * @param {OwnerType | string} [owner=OwnerType.MINE] single account ID (CScript or address) or reserved words 'mine' to list history for all owned accounts or 'all' to list whole DB + * @param {ListFutureHistoryOptions} [options] + * @param {number} [options.maxBlockHeight] Optional height to iterate from (downto genesis block), (default = chaintip). + * @param {number} [options.depth] Maximum depth, from the genesis block is the default + * @param {string} [options.token] Filter by token + * @param {number} [options.limit=100] Maximum number of records to return, 100 by default + * @return {Promise} + */ + async listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise { + return await this.client.call('listfutureswaphistory', [], 'number') + } } export interface AccountPagination { @@ -619,3 +634,17 @@ export interface GetFutureInfo { owner: string values: Array> } + +export interface ListFutureHistoryOptions { + maxBlockHeight: number + depth: number + token: string + limit: number +} + +export interface FutureHistory { + height: number + address: string + source: string + destination: string +} From 77e19d8656c2385d96630fd7f37202202ac8eb4e Mon Sep 17 00:00:00 2001 From: surangap Date: Fri, 1 Apr 2022 15:09:40 +0800 Subject: [PATCH 10/32] Updated futureswap API. --- docs/node/CATEGORIES/08-account.md | 33 ++----------------- .../src/category/account.ts | 21 ++---------- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index ae12b647bd..d9be7b91f5 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -479,7 +479,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: number + destination: string } interface UTXO { @@ -500,7 +500,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: number + destination: string } interface UTXO { @@ -544,33 +544,4 @@ interface FutureInfo { source: string destination: string } -``` - -## listFutureSwapHistory - -Returns information about future swap history. - -```ts title="client.account.listFutureSwapHistory()" -interface account { - listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise -} - -enum OwnerType { - MINE = 'mine', - ALL = 'all' -} - -interface ListFutureHistoryOptions { - maxBlockHeight: number - depth: number - token: string - limit: number -} - -interface FutureHistory { - height: number - address: string - source: string - destination: string -} ``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 28d1abfa80..ab5bcb2074 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -395,7 +395,7 @@ export class Account { * @param {FutureSwap} future * @param {string} future.address Address to fund contract and receive resulting token * @param {string} future.amount Amount to send in amount@token format - * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {string} [future.destination] Expected dToken if DUSD supplied * @param {UTXO[]} [options.utxos = []] * @param {string} options.utxos.txid * @param {number} options.utxos.vout @@ -411,7 +411,7 @@ export class Account { * @param {FutureSwap} future * @param {string} future.address Address to fund contract and receive resulting token * @param {string} future.amount Amount to send in amount@token format - * @param {number} [future.destination] Expected dToken if DUSD supplied + * @param {string} [future.destination] Expected dToken if DUSD supplied * @param {UTXO[]} [options.utxos = []] * @param {string} options.utxos.txid * @param {number} options.utxos.vout @@ -438,21 +438,6 @@ export class Account { async getPendingFutureSwaps (): Promise { return await this.client.call('getpendingfutureswaps', [], 'number') } - - /** - * Returns information about future swap history. - * - * @param {OwnerType | string} [owner=OwnerType.MINE] single account ID (CScript or address) or reserved words 'mine' to list history for all owned accounts or 'all' to list whole DB - * @param {ListFutureHistoryOptions} [options] - * @param {number} [options.maxBlockHeight] Optional height to iterate from (downto genesis block), (default = chaintip). - * @param {number} [options.depth] Maximum depth, from the genesis block is the default - * @param {string} [options.token] Filter by token - * @param {number} [options.limit=100] Maximum number of records to return, 100 by default - * @return {Promise} - */ - async listFutureSwapHistory (owner: OwnerType | string = OwnerType.MINE, options: ListFutureHistoryOptions): Promise { - return await this.client.call('listfutureswaphistory', [], 'number') - } } export interface AccountPagination { @@ -621,7 +606,7 @@ export interface BurnInfo { export interface FutureSwap { address: string amount: string - destination: number + destination: string } export interface FutureInfo { From a6bcedddf4da6399bc6ca99f2bcfb95d384e6b5c Mon Sep 17 00:00:00 2001 From: surangap Date: Sun, 3 Apr 2022 21:43:43 +0800 Subject: [PATCH 11/32] Added futureswap tests. --- docs/node/CATEGORIES/08-account.md | 8 +- .../category/account/futureswap.test.ts | 332 ++++++++++++++++++ .../src/category/account.ts | 8 +- packages/jellyfish-testing/src/token.ts | 5 + .../src/containers/DeFiDContainer.ts | 2 +- 5 files changed, 350 insertions(+), 5 deletions(-) create mode 100644 packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index d9be7b91f5..ab7b617fcb 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -464,6 +464,10 @@ interface BurnInfo { * Amount of tokens that are paid back */ paybacktokens: string[] + /** + * Amount of tokens burned due to futureswap + */ + dfip2203: string[] } ``` @@ -479,7 +483,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: string + destination?: string } interface UTXO { @@ -500,7 +504,7 @@ interface account { interface FutureSwap { address: string amount: string - destination: string + destination?: string } interface UTXO { diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts new file mode 100644 index 0000000000..dc551e8fc2 --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -0,0 +1,332 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import BigNumber from 'bignumber.js' +import { Testing } from '@defichain/jellyfish-testing' +import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' + +const container = new MasterNodeRegTestContainer() +const testing = Testing.create(container) +let collateralAddress: string +let oracleId: string +let idDUSD: string +let idTSLA: string +// let idAMZN: string +// let idBTC: string +const attributeKey = 'ATTRIBUTES' +// let key: string +let futInterval: number +let futRewardPercentage: number +const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' + +async function setup (): Promise { + collateralAddress = await testing.generateAddress() + await testing.token.dfi({ address: collateralAddress, amount: 300000 }) + await testing.token.create({ symbol: 'BTC', collateralAddress }) + await testing.generate(1) + await testing.token.mint({ symbol: 'BTC', amount: 20000 }) + await testing.generate(1) + + // loan scheme + await testing.container.call('createloanscheme', [100, 1, 'default']) + await testing.generate(1) + + // price oracle + const priceFeeds = [ + { token: 'DFI', currency: 'USD' }, + { token: 'BTC', currency: 'USD' }, + { token: 'TSLA', currency: 'USD' }, + { token: 'AMZN', currency: 'USD' }, + { token: 'DUSD', currency: 'USD' } + ] + + const addr = await testing.generateAddress() + oracleId = await testing.rpc.oracle.appointOracle(addr, priceFeeds, { weightage: 1 }) + await testing.generate(1) + + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '1@DFI', currency: 'USD' }, + { tokenAmount: '10000@BTC', currency: 'USD' }, + { tokenAmount: '2@TSLA', currency: 'USD' }, + { tokenAmount: '4@AMZN', currency: 'USD' }, + { tokenAmount: '1@DUSD', currency: 'USD' } + ] + } + ) + await testing.generate(1) + + // collateral tokens + await testing.rpc.loan.setCollateralToken({ + token: 'DFI', + factor: new BigNumber(1), + fixedIntervalPriceId: 'DFI/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setCollateralToken({ + token: 'BTC', + factor: new BigNumber(0.5), + fixedIntervalPriceId: 'BTC/USD' + }) + await testing.generate(1) + + // loan token + await testing.rpc.loan.setLoanToken({ + symbol: 'TSLA', + fixedIntervalPriceId: 'TSLA/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setLoanToken({ + symbol: 'AMZN', + fixedIntervalPriceId: 'AMZN/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setLoanToken({ + symbol: 'DUSD', + fixedIntervalPriceId: 'DUSD/USD' + }) + await testing.generate(1) + + // idBTC = await testing.token.getTokenId('BTC') + idTSLA = await testing.token.getTokenId('TSLA') + // idAMZN = await testing.token.getTokenId('AMZN') + idDUSD = await testing.token.getTokenId('DUSD') + + // create a vault and take loans + const vaultAddr = await testing.generateAddress() + const vaultId = await testing.rpc.loan.createVault({ + ownerAddress: vaultAddr, + loanSchemeId: 'default' + }) + await testing.generate(1) + + await testing.rpc.loan.depositToVault({ + vaultId: vaultId, from: collateralAddress, amount: '100000@DFI' + }) + + // wait till the price valid. + await testing.container.waitForPriceValid('TSLA/USD') + + // take multiple loans + await testing.rpc.loan.takeLoan({ + vaultId: vaultId, + to: collateralAddress, + amounts: ['300@TSLA', '500@DUSD', '100@AMZN'] + }) + await testing.generate(1) + + // Futures setup + // set the dfip2203/active to false + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + + // set dfip2203 params + futInterval = 25 + futRewardPercentage = 0.05 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': futRewardPercentage.toString(), 'v0/params/dfip2203/block_period': futInterval.toString() } }) + await testing.generate(1) + + // activat the dfip2203/active now + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) + await testing.generate(1) + + // Retrive and verify gov vars + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('true') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(futRewardPercentage.toString()) + expect(attributes.ATTRIBUTES['v0/params/dfip2203/block_period']).toStrictEqual(futInterval.toString()) +} + +async function getNextSettleBlock (): Promise { + const blockCount = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = blockCount + (futInterval - (blockCount % futInterval)) + return nextSettleBlock +} + +describe('futureSwap', () => { + beforeEach(async () => { + await testing.container.start() + await testing.container.waitForWalletCoinbaseMaturity() + await setup() + }) + + afterEach(async () => { + await testing.container.stop() + }) + + it('should create futureswap dtoken to dusd', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@TSLA') + expect(pendingFutures[0].destination).toStrictEqual('DUSD') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([]) + } + } + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // move to next settle block + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + // check future settled + { + // calclulate minted DUSD. dtoken goes for a discount. + const mintedDUSD = (1 - futRewardPercentage) * 2 * swapAmount // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + }) + + it('should create futureswap dusd to dtoken', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([]) + } + } + + // get minted TSLA + const tslaMintedBefore = (await testing.rpc.token.getToken(idTSLA))[idTSLA].minted + + // move to next settle block + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + // check future settled + { + // calclulate minted TSLA. dtoken goes for a premium. + const mintedTSLA = new BigNumber((1 / (1 + futRewardPercentage)) * (1 / 2) * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1/(1 + reward percentage)) * (DUSDTSLA) value * DUSD swap amount; + const tslaMintedAfter = (await testing.rpc.token.getToken(idTSLA))[idTSLA].minted + expect(tslaMintedAfter).toStrictEqual(tslaMintedBefore.plus(mintedTSLA)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedTSLA.toString() + '@TSLA']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedTSLA.toString() + '@TSLA']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) + }) +}) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index ab5bcb2074..41cb2e7f3f 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -402,7 +402,7 @@ export class Account { * @return {Promise} */ async futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('futureswap', [future, utxos], 'number') + return await this.client.call('futureswap', [future.address, future.amount, future.destination, utxos], 'number') } /** @@ -601,12 +601,16 @@ export interface BurnInfo { * Amount of tokens that are paid back */ paybacktokens: string[] + /** + * Amount of tokens burned due to futureswap + */ + dfip2203: string[] } export interface FutureSwap { address: string amount: string - destination: string + destination?: string } export interface FutureInfo { diff --git a/packages/jellyfish-testing/src/token.ts b/packages/jellyfish-testing/src/token.ts index 76807f678b..1a17fd84a7 100644 --- a/packages/jellyfish-testing/src/token.ts +++ b/packages/jellyfish-testing/src/token.ts @@ -43,6 +43,11 @@ export class TestingToken { const to = { [address]: [account] } return await this.rpc.account.sendTokensToAddress({}, to) } + + async getTokenId (symbol: string): Promise { + const tokenInfo = await this.rpc.token.getToken(symbol) + return Object.keys(tokenInfo)[0] + } } interface TestingTokenCreate { diff --git a/packages/testcontainers/src/containers/DeFiDContainer.ts b/packages/testcontainers/src/containers/DeFiDContainer.ts index f6e7402e24..d922137df4 100644 --- a/packages/testcontainers/src/containers/DeFiDContainer.ts +++ b/packages/testcontainers/src/containers/DeFiDContainer.ts @@ -35,7 +35,7 @@ export abstract class DeFiDContainer extends DockerContainer { if (process?.env?.DEFICHAIN_DOCKER_IMAGE !== undefined) { return process.env.DEFICHAIN_DOCKER_IMAGE } - return 'defi/defichain:master-2a236bb79' + return 'defi/defichain:master-35ad71b82' } public static readonly DefaultStartOptions = { From 9f8f3a83f96948452a56b3ff17333fdd3e7294b9 Mon Sep 17 00:00:00 2001 From: surangap Date: Mon, 4 Apr 2022 19:02:09 +0800 Subject: [PATCH 12/32] Updated tests. --- .../category/account/futureswap.test.ts | 399 +++++++++++++++++- .../containers/RegTestContainer/Masternode.ts | 24 ++ 2 files changed, 422 insertions(+), 1 deletion(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index dc551e8fc2..33731026d2 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -2,6 +2,7 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import BigNumber from 'bignumber.js' import { Testing } from '@defichain/jellyfish-testing' import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' +import { RpcApiError } from '@defichain/jellyfish-api-core' const container = new MasterNodeRegTestContainer() const testing = Testing.create(container) @@ -213,7 +214,7 @@ describe('futureSwap', () => { // check future settled { // calclulate minted DUSD. dtoken goes for a discount. - const mintedDUSD = (1 - futRewardPercentage) * 2 * swapAmount // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) @@ -244,6 +245,232 @@ describe('futureSwap', () => { expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) }) + it('should create futureswap dtoken to dusd just before the next settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // move to next settle block - 1 + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount() - 1) + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check future settled + { + // calclulate minted DUSD. dtoken goes for a discount. + const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + }) + + it('should consider new oracle active price, if changed before futureswap execution', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + let blockHeight = await testing.rpc.blockchain.getBlockCount() + let nextSettleBlock = await getNextSettleBlock() + + // move to next settle block for better duration for the oracle price to kick in + await testing.generate(nextSettleBlock - blockHeight) + blockHeight = await testing.rpc.blockchain.getBlockCount() + nextSettleBlock = await getNextSettleBlock() + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // change the oracle price + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '2.2@TSLA', currency: 'USD' } + ] + } + ) + await testing.generate(1) + await testing.container.waitForActivePrice('TSLA/USD', '2.2') + + const blockHeightAfter = await testing.rpc.blockchain.getBlockCount() + + // check next settle block is not reached yet + expect(blockHeightAfter).toBeLessThan(nextSettleBlock) + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // move to nextSettleBlock + await testing.generate(nextSettleBlock - blockHeightAfter) + + // check future settled + { + // calclulate minted DUSD. dtoken goes for a discount. + const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2.2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + }) + + it('should refund if the oracle price is invalid at futureswap execution block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + let blockHeight = await testing.rpc.blockchain.getBlockCount() + let nextSettleBlock = await getNextSettleBlock() + + // move to next settle block + await testing.generate(nextSettleBlock - blockHeight) + blockHeight = await testing.rpc.blockchain.getBlockCount() + nextSettleBlock = await getNextSettleBlock() + const nextPriceBlock = await testing.container.getImmediatePriceBlockBeforeBlock('TSLA/USD', nextSettleBlock) + + // create the futureswap + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the futureswap is in effect + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + + // move to nextPriceBlock - 1 + await testing.generate(nextPriceBlock - 1 - await testing.rpc.blockchain.getBlockCount()) + + // change the oracle price + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '3@TSLA', currency: 'USD' } + ] + } + ) + await testing.generate(1) + { + // now check the price invalid + const priceDataInvalid = await testing.rpc.oracle.getFixedIntervalPrice('TSLA/USD') + expect(priceDataInvalid.isLive).toBeFalsy() + } + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // move to nextSettleBlock + await testing.generate(nextSettleBlock - nextPriceBlock) + + // check price is still invalid + { + const priceDataInvalid = await testing.rpc.oracle.getFixedIntervalPrice('TSLA/USD') + expect(priceDataInvalid.isLive).toBeFalsy() + } + + // check futureswap is not executed. + { + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([]) + }) + it('should create futureswap dusd to dtoken', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) @@ -329,4 +556,174 @@ describe('futureSwap', () => { const burnAfter = await testing.rpc.account.getBurnInfo() expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) }) + + it('should not create futureswap when DFIP2203 is not active', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // deactivate DFIP2203 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('false') + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + + const promise = testing.rpc.account.futureSwap(fswap) + + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDFIP2203 not currently active\', code: -32600, method: futureswap') + }) + + it('should refund the futureswap if DFIP2203 is disabled before execution', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // create the futureswap + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const nextSettleBlock = await getNextSettleBlock() + + // check the futureswap is in effect + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + + // get minted DUSD + const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + + // deactivate DFIP2203 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('false') + + // move to nextSettleBlock + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + // check futureswap is not executed. + { + const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted + expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore) + + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + } + } + + // check burn + const burnAfter = await testing.rpc.account.getBurnInfo() + expect(burnAfter.dfip2203).toStrictEqual([]) + }) + + it('should not create futureswap when invalid inputs given', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + { + // zero source amount is given + const fswap: FutureSwap = { + address: tslaAddress, + amount: '0@TSLA' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: futureswap') + } + { + // negative source amount is given + const fswap: FutureSwap = { + address: tslaAddress, + amount: '-1@TSLA' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: futureswap') + } + { + // invlaid source dtoken + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@INVALID' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: futureswap') + } + { + // destination is given when futureswap dtoken to dusd + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@TSLA', + destination: 'DUSD' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDestination should not be set when source amount is a dToken\', code: -32600, method: futureswap') + } + { + // INVALID destination is given when futureswap dusd to dtoken + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@DUSD', + destination: 'INVALID' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Destination token not found\', code: -5, method: futureswap') + } + }) + + it('should not create futureswap when DFIP2203 is disabled for the dtoken', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + // deactivate DFIP2203 for dtoken + const key = 'v0/token/' + idTSLA + '/dfip2203' + + await testing.rpc.masternode.setGov({ [attributeKey]: { [key]: 'false' } }) + await testing.generate(1) + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES[key]).toStrictEqual('false') + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDFIP2203 currently disabled for token 2\', code: -32600, method: futureswap') + }) }) diff --git a/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts b/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts index 78d71b6d03..1a5f4dc2ec 100644 --- a/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts +++ b/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts @@ -239,6 +239,14 @@ export class MasterNodeRegTestContainer extends RegTestContainer { }, timeout, 100, 'waitForPriceInvalid') } + /** + * Wait for valut state + * + * @param {string} vaultId + * @param {string} state + * @param {number} [timeout=30000] in ms + * @return {Promise} + */ async waitForVaultState (vaultId: string, state: string, timeout = 30000): Promise { return await waitForCondition(async () => { const vault = await this.call('getvault', [vaultId]) @@ -250,6 +258,22 @@ export class MasterNodeRegTestContainer extends RegTestContainer { }, timeout, 100, 'waitForVaultState') } + /** + * Get next price block before the given target block + * + * @param {string} fixedIntervalPriceId + * @param {number} [targetBlock] + * @return {Promise} + */ + async getImmediatePriceBlockBeforeBlock (fixedIntervalPriceId: string, targetBlock: number): Promise { + const data: any = await this.call('getfixedintervalprice', [fixedIntervalPriceId]) + let nextPriceBlock = data.nextPriceBlock as number + while (nextPriceBlock < targetBlock) { + nextPriceBlock += 6 // 1 hour in regtest is 6 blocks + } + return nextPriceBlock + } + /** * Wait for active price * From 7e9feaa35efdfc4d31f73a145088cac76c553e96 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Tue, 5 Apr 2022 09:11:14 +0530 Subject: [PATCH 13/32] Addted a test to withdraw fututre swap --- .../category/account/futureswap.test.ts | 58 +++++++++++++++++++ .../src/category/account.ts | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index 33731026d2..945e8849d7 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -557,6 +557,64 @@ describe('futureSwap', () => { expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) }) + it('should withdraw futureswap', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + } + + const withdraw = 0.5 + const fswapWithdraw: FutureSwap = { + address: tslaAddress, + amount: withdraw.toString() + '@DUSD', + destination: 'TSLA' + } + + // Withdraw half of future swap + { + await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) + await testing.generate(1) + } + + // check the future after withdraw half + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdraw).toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + } + + // Withdraw second half of future swap + { + await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) + await testing.generate(1) + } + + // check the future after withdrawing all + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + } + }) + it('should not create futureswap when DFIP2203 is not active', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 41cb2e7f3f..cf928298b9 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -418,7 +418,7 @@ export class Account { * @return {Promise} */ async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('withdrawfutureswap', [future, utxos], 'number') + return await this.client.call('withdrawfutureswap', [future.address, future.amount, future.destination, utxos], 'number') } /** From 247656edf1095c6626f912776ff6a867eb285c1e Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Tue, 5 Apr 2022 09:30:37 +0530 Subject: [PATCH 14/32] Revert "Addted a test to withdraw fututre swap" This reverts commit 4d137e24a06aaaa501b751afd6cb8af2ae274c24. --- .../category/account/futureswap.test.ts | 58 ------------------- .../src/category/account.ts | 2 +- 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index 945e8849d7..33731026d2 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -557,64 +557,6 @@ describe('futureSwap', () => { expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) }) - it('should withdraw futureswap', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) - await testing.generate(1) - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', - destination: 'TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') - expect(pendingFutures[0].destination).toStrictEqual('TSLA') - } - - const withdraw = 0.5 - const fswapWithdraw: FutureSwap = { - address: tslaAddress, - amount: withdraw.toString() + '@DUSD', - destination: 'TSLA' - } - - // Withdraw half of future swap - { - await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) - await testing.generate(1) - } - - // check the future after withdraw half - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdraw).toFixed(8) + '@DUSD') - expect(pendingFutures[0].destination).toStrictEqual('TSLA') - } - - // Withdraw second half of future swap - { - await testing.rpc.account.withdrawFutureSwap(fswapWithdraw) - await testing.generate(1) - } - - // check the future after withdrawing all - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - } - }) - it('should not create futureswap when DFIP2203 is not active', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index cf928298b9..41cb2e7f3f 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -418,7 +418,7 @@ export class Account { * @return {Promise} */ async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('withdrawfutureswap', [future.address, future.amount, future.destination, utxos], 'number') + return await this.client.call('withdrawfutureswap', [future, utxos], 'number') } /** From 8a71f888003289de8ededcb883499ff749ea6149 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 5 Apr 2022 19:02:55 +0800 Subject: [PATCH 15/32] Fixed failing tests due to ain 1159. --- .../category/account/getBurnInfo.test.ts | 3 +- .../category/loan/paybackLoan.test.ts | 166 ++++++++++++++++-- .../txn/txn_builder_loan_payback_loan.test.ts | 4 +- 3 files changed, 157 insertions(+), 16 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/getBurnInfo.test.ts b/packages/jellyfish-api-core/__tests__/category/account/getBurnInfo.test.ts index 98d032f16c..3fb4226b4f 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/getBurnInfo.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/getBurnInfo.test.ts @@ -56,6 +56,7 @@ it('should getBurnInfo', async () => { paybacktokens: [], dexfeetokens: [], dfipaybackfee: new BigNumber(0), - dfipaybacktokens: [] + dfipaybacktokens: [], + dfip2203: [] }) }) diff --git a/packages/jellyfish-api-core/__tests__/category/loan/paybackLoan.test.ts b/packages/jellyfish-api-core/__tests__/category/loan/paybackLoan.test.ts index 955100e11f..f819254d52 100644 --- a/packages/jellyfish-api-core/__tests__/category/loan/paybackLoan.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/loan/paybackLoan.test.ts @@ -1152,7 +1152,7 @@ describe('paybackLoan before FortCanningHeight', () => { await tGroupFCH.waitForSync() const promise = testing.rpc.loan.paybackLoan(loanMetadata) - await expect(promise).rejects.toThrow('RpcApiError: \'Test PaybackLoanV2Tx execution failed:\nCannot payback this amount of loan for TSLA, either payback full amount or less than this amount!\', code: -32600, method: paybackloan') + await expect(promise).rejects.toThrow('RpcApiError: \'Test PaybackLoanTx execution failed:\nCannot payback this amount of loan for TSLA, either payback full amount or less than this amount!\', code: -32600, method: paybackloan') await testing.container.waitForBlockHeight(fchBlockHeight) const blockInfo = await testing.rpc.blockchain.getBlockchainInfo() @@ -1214,7 +1214,7 @@ describe('paybackloan for any token', () => { const container = new MasterNodeRegTestContainer() const testing = Testing.create(container) - const dusdLoanAmount = 5000 + const dusdLoanAmount = 50000 const tslaLoanAmount = 10 const loanSchemeId = 'scheme' const attributeKey = 'ATTRIBUTES' @@ -1566,7 +1566,11 @@ describe('paybackloan for any token', () => { const dfiPaybackAmount = dusdLoanAmount + 1000 const defaultPenaltyRate = 0.01 const dfiEffectPriceAfterPenaltyRate = 1 * (1 - defaultPenaltyRate) - const dfiNeededToPayOffDusd = dusdLoanAmountBefore.dividedBy(dfiEffectPriceAfterPenaltyRate).decimalPlaces(8, BigNumber.ROUND_CEIL) + let dfiNeededToPayOffDusd = dusdLoanAmountBefore.dividedBy(dfiEffectPriceAfterPenaltyRate) + + if (dfiNeededToPayOffDusd.multipliedBy(dfiEffectPriceAfterPenaltyRate) !== dusdLoanAmountBefore) { + dfiNeededToPayOffDusd = dfiNeededToPayOffDusd.plus(0.00000001) + } await testing.rpc.loan.paybackLoan({ vaultId: vaultId, @@ -1582,7 +1586,7 @@ describe('paybackloan for any token', () => { const totalDfiPenalty = dfiNeededToPayOffDusd.multipliedBy(defaultPenaltyRate) const totalDusdPaybackAmount = dusdLoanAmountBefore const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.paybackburn.toFixed(8)).toStrictEqual(totalDusdPaybackAmount.plus(totalDfiPenalty).toFixed(8)) + expect(burnInfoAfter.paybackburn.toFixed(8)).toStrictEqual(dfiNeededToPayOffDusd.toFixed(8)) expect(burnInfoAfter.dfipaybackfee.toFixed(8)).toStrictEqual(totalDfiPenalty.toFixed(8, BigNumber.ROUND_FLOOR)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${totalDusdPaybackAmount.toFixed(8)}@DUSD`]) @@ -1639,7 +1643,7 @@ describe('paybackloan for any token', () => { const totalDfiPenalty = new BigNumber(dfiPaybackAmount).multipliedBy(penaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount).toFixed(8)}@DFI`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(totalDfiPenalty) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${dusdPayback.toFixed(8)}@DUSD`]) @@ -1655,6 +1659,37 @@ describe('paybackloan for any token', () => { it('should be able to payback DUSD loan using TSLA - use PaybackLoanMetadataV2', async () => { await takeTslaTokensToPayback() + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-TSLA + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'TSLA' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-TSLA + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20 }, + b: { symbol: 'TSLA', amount: 10 } + }) + await testing.generate(1) + } + const dusdInfo = await testing.rpc.token.getToken('DUSD') const dusdId: string = Object.keys(dusdInfo)[0] const tslaInfo = await testing.rpc.token.getToken('TSLA') @@ -1705,7 +1740,7 @@ describe('paybackloan for any token', () => { const totalTslaPenalty = new BigNumber(tslaPaybackAmount).multipliedBy(penaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(tslaPaybackAmount).toFixed(8)}@TSLA`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${totalTslaPenalty.toFixed(8)}@TSLA`]) expect(burnInfoAfter.paybacktokens).toStrictEqual([`${dusdPayback.toFixed(8)}@DUSD`]) @@ -1721,6 +1756,37 @@ describe('paybackloan for any token', () => { it('should be able to payback DUSD loan using both TSLA and DFI - use PaybackLoanMetadataV2', async () => { await takeTslaTokensToPayback() + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-TSLA + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'TSLA' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-TSLA + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20 }, + b: { symbol: 'TSLA', amount: 10 } + }) + await testing.generate(1) + } + const dfiInfo = await testing.rpc.token.getToken('DFI') const dfiId: string = Object.keys(dfiInfo)[0] const dusdInfo = await testing.rpc.token.getToken('DUSD') @@ -1786,7 +1852,7 @@ describe('paybackloan for any token', () => { const totalDfiPenalty = new BigNumber(dfiPaybackAmount).multipliedBy(dfiPenaltyRate) const totalTslaPenalty = new BigNumber(tslaPaybackAmount).multipliedBy(tslaPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount).toFixed(8)}@DFI`, `${new BigNumber(tslaPaybackAmount).toFixed(8)}@TSLA`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(totalDfiPenalty) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${dusdPaybackByDfi.toFixed(8)}@DUSD`]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${totalTslaPenalty.toFixed(8)}@TSLA`]) @@ -1825,6 +1891,51 @@ describe('paybackloan for any token', () => { }) await testing.generate(1) + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-TSLA + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'TSLA' + }) + await testing.generate(1) + + // create DUSD-BTC + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'BTC' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-TSLA + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20 }, + b: { symbol: 'TSLA', amount: 10 } + }) + await testing.generate(1) + + // add DUSD-BTC + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20000 }, + b: { symbol: 'BTC', amount: 2 } + }) + await testing.generate(1) + } + const dusdInfo = await testing.rpc.token.getToken('DUSD') const dusdId: string = Object.keys(dusdInfo)[0] const tslaInfo = await testing.rpc.token.getToken('TSLA') @@ -1890,7 +2001,7 @@ describe('paybackloan for any token', () => { const totalTslaPenalty = new BigNumber(tslaPaybackAmount).multipliedBy(tslaPenaltyRate) const totalBtcPenalty = new BigNumber(btcPaybackAmount).multipliedBy(btcPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(tslaPaybackAmount).toFixed(8)}@TSLA`, `${new BigNumber(btcPaybackAmount).toFixed(8)}@BTC`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(new BigNumber(0)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${totalTslaPenalty.toFixed(8)}@TSLA`, `${totalBtcPenalty.toFixed(8)}@BTC`]) @@ -2016,7 +2127,7 @@ describe('paybackloan for any token', () => { const totalDfiPenalty = new BigNumber(dfiPaybackAmount).multipliedBy(penaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount).toFixed(8)}@DFI`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(totalDfiPenalty) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${tslaPayback.toFixed(8)}@TSLA`]) @@ -2105,7 +2216,7 @@ describe('paybackloan for any token', () => { const dfiPenaltyForTslaLoan = new BigNumber(dfiPaybackAmount).multipliedBy(tslaPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount * 2).toFixed(8)}@DFI`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(dfiPenaltyForDusdLoan.plus(dfiPenaltyForTslaLoan)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${dusdPayback.toFixed(8)}@DUSD`, `${tslaPayback.toFixed(8)}@TSLA`]) @@ -2142,6 +2253,37 @@ describe('paybackloan for any token', () => { }) await testing.generate(1) + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-BTC + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'BTC' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-BTC + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20000 }, + b: { symbol: 'BTC', amount: 2 } + }) + await testing.generate(1) + } + const tslaTakeLoanBlockHeight = await testing.rpc.blockchain.getBlockCount() await testing.rpc.loan.takeLoan({ vaultId: vaultId, @@ -2222,7 +2364,7 @@ describe('paybackloan for any token', () => { const btcPenaltyForTslaLoan = new BigNumber(btcPaybackAmount).multipliedBy(tslaPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(btcPaybackAmount * 2).toFixed(8)}@BTC`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(new BigNumber(0)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${btcPenaltyForDusdLoan.plus(btcPenaltyForTslaLoan).toFixed(8)}@BTC`]) @@ -2331,7 +2473,7 @@ describe('paybackloan for any token', () => { from: vaultOwnerAddress }) - await expect(payBackPromise).rejects.toThrow('RpcApiError: \'Test PaybackLoanTx execution failed:\nThere is no loan on token (DUSD) in this vault!\', code: -32600, method: paybackloan') + await expect(payBackPromise).rejects.toThrow('RpcApiError: \'Test PaybackLoanTx execution failed:\nPayback of loan via DFI token is not currently active\', code: -32600, method: paybackloan') }) it('should not be able to payback DUSD loan using TSLA - without PaybackLoanMetadataV2', async () => { diff --git a/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts b/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts index de92d16ba5..662a82aecc 100644 --- a/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts +++ b/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts @@ -1288,7 +1288,6 @@ describe('paybackLoan for any token', () => { const totalDfiPenalty = new BigNumber(dfiPaybackAmount).multipliedBy(penaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount).toFixed(8)}@DFI`]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(totalDfiPenalty) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${dusdPayback.toFixed(8)}@DUSD`]) @@ -1376,7 +1375,6 @@ describe('paybackLoan for any token', () => { const dfiPenaltyForTslaLoan = new BigNumber(dfiPaybackAmount).multipliedBy(tslaPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount * 2).toFixed(8)}@DFI`]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(dfiPenaltyForDusdLoan.plus(dfiPenaltyForTslaLoan)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${dusdPayback.toFixed(8)}@DUSD`, `${tslaPayback.toFixed(8)}@TSLA`]) @@ -1501,6 +1499,6 @@ describe('paybackLoan for any token', () => { }, script) const payBackPromise = sendTransaction(testing.container, txn) - await expect(payBackPromise).rejects.toThrow('DeFiDRpcError: \'PaybackLoanTx: There is no loan on token (DUSD) in this vault! (code 16)\', code: -26') + await expect(payBackPromise).rejects.toThrow('DeFiDRpcError: \'PaybackLoanTx: Payback of loan via DFI token is not currently active (code 16)\', code: -26') }) }) From 2f53c1cabd1263e8356e89d81979ff1124971454 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Tue, 5 Apr 2022 16:43:44 +0530 Subject: [PATCH 16/32] Added withdraw future swap pass test cases --- .../account/withdrawFutureSwap.test.ts | 363 ++++++++++++++++++ .../src/category/account.ts | 2 +- 2 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts new file mode 100644 index 0000000000..5875341eec --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -0,0 +1,363 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import BigNumber from 'bignumber.js' +import { Testing } from '@defichain/jellyfish-testing' +import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' + +const container = new MasterNodeRegTestContainer() +const testing = Testing.create(container) +let collateralAddress: string +let oracleId: string +// let idDUSD: string +// let idTSLA: string +// let idAMZN: string +// let idBTC: string +const attributeKey = 'ATTRIBUTES' +// let key: string +let futInterval: number +let futRewardPercentage: number +const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' + +async function setup (): Promise { + collateralAddress = await testing.generateAddress() + await testing.token.dfi({ address: collateralAddress, amount: 300000 }) + await testing.token.create({ symbol: 'BTC', collateralAddress }) + await testing.generate(1) + await testing.token.mint({ symbol: 'BTC', amount: 20000 }) + await testing.generate(1) + + // loan scheme + await testing.container.call('createloanscheme', [100, 1, 'default']) + await testing.generate(1) + + // price oracle + const priceFeeds = [ + { token: 'DFI', currency: 'USD' }, + { token: 'BTC', currency: 'USD' }, + { token: 'TSLA', currency: 'USD' }, + { token: 'AMZN', currency: 'USD' }, + { token: 'DUSD', currency: 'USD' } + ] + + const addr = await testing.generateAddress() + oracleId = await testing.rpc.oracle.appointOracle(addr, priceFeeds, { weightage: 1 }) + await testing.generate(1) + + const timestamp = Math.floor(new Date().getTime() / 1000) + await testing.rpc.oracle.setOracleData( + oracleId, + timestamp, + { + prices: [ + { tokenAmount: '1@DFI', currency: 'USD' }, + { tokenAmount: '10000@BTC', currency: 'USD' }, + { tokenAmount: '2@TSLA', currency: 'USD' }, + { tokenAmount: '4@AMZN', currency: 'USD' }, + { tokenAmount: '1@DUSD', currency: 'USD' } + ] + } + ) + await testing.generate(1) + + // collateral tokens + await testing.rpc.loan.setCollateralToken({ + token: 'DFI', + factor: new BigNumber(1), + fixedIntervalPriceId: 'DFI/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setCollateralToken({ + token: 'BTC', + factor: new BigNumber(0.5), + fixedIntervalPriceId: 'BTC/USD' + }) + await testing.generate(1) + + // loan token + await testing.rpc.loan.setLoanToken({ + symbol: 'TSLA', + fixedIntervalPriceId: 'TSLA/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setLoanToken({ + symbol: 'AMZN', + fixedIntervalPriceId: 'AMZN/USD' + }) + await testing.generate(1) + + await testing.rpc.loan.setLoanToken({ + symbol: 'DUSD', + fixedIntervalPriceId: 'DUSD/USD' + }) + await testing.generate(1) + + // idBTC = await testing.token.getTokenId('BTC') + idTSLA = await testing.token.getTokenId('TSLA') + // idAMZN = await testing.token.getTokenId('AMZN') + idDUSD = await testing.token.getTokenId('DUSD') + + // create a vault and take loans + const vaultAddr = await testing.generateAddress() + const vaultId = await testing.rpc.loan.createVault({ + ownerAddress: vaultAddr, + loanSchemeId: 'default' + }) + await testing.generate(1) + + await testing.rpc.loan.depositToVault({ + vaultId: vaultId, from: collateralAddress, amount: '100000@DFI' + }) + + // wait till the price valid. + await testing.container.waitForPriceValid('TSLA/USD') + + // take multiple loans + await testing.rpc.loan.takeLoan({ + vaultId: vaultId, + to: collateralAddress, + amounts: ['300@TSLA', '500@DUSD', '100@AMZN'] + }) + await testing.generate(1) + + // Futures setup + // set the dfip2203/active to false + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + await testing.generate(1) + + // set dfip2203 params + futInterval = 25 + futRewardPercentage = 0.05 + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': futRewardPercentage.toString(), 'v0/params/dfip2203/block_period': futInterval.toString() } }) + await testing.generate(1) + + // activat the dfip2203/active now + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) + await testing.generate(1) + + // Retrive and verify gov vars + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('true') + expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(futRewardPercentage.toString()) + expect(attributes.ATTRIBUTES['v0/params/dfip2203/block_period']).toStrictEqual(futInterval.toString()) +} + +async function getNextSettleBlock (): Promise { + const blockCount = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = blockCount + (futInterval - (blockCount % futInterval)) + return nextSettleBlock +} + +describe('withdrawFutureSwap', () => { + beforeEach(async () => { + await testing.container.start() + await testing.container.waitForWalletCoinbaseMaturity() + await setup() + }) + + afterEach(async () => { + await testing.container.stop() + }) + + it('should withdraw futureswap dtoken to dusd - before settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const withdrawAmount = swapAmount / 2 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@TSLA' + } + + // withdraw half of the future swap + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after withdrawing a half + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@TSLA') + expect(pendingFutures[0].destination).toStrictEqual('DUSD') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@TSLA']) + } + } + + // withdraw second half of the future swap + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future after withdrawing all + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([(withdrawAmount * 2).toFixed(8) + '@TSLA']) + } + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await getNextSettleBlock() + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + + it('should withdraw futureswap dusd to dtoken - before settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const withdrawAmount = swapAmount / 2 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@DUSD', + destination: 'TSLA' + } + + // withdraw half of the future swap + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after withdrawing a half + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@DUSD']) + } + } + + // withdraw second half of the future swap + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future after withdrawing all + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([(withdrawAmount * 2).toFixed(8) + '@DUSD']) + } + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await getNextSettleBlock() + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) +}) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 41cb2e7f3f..cf928298b9 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -418,7 +418,7 @@ export class Account { * @return {Promise} */ async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('withdrawfutureswap', [future, utxos], 'number') + return await this.client.call('withdrawfutureswap', [future.address, future.amount, future.destination, utxos], 'number') } /** From efb7d528a0e87baaa88359d5e522f81f096080a0 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 5 Apr 2022 19:50:30 +0800 Subject: [PATCH 17/32] Updated tests. --- .../category/account/futureswap.test.ts | 29 ++++++++++++++----- .../src/category/account.ts | 4 ++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts index 33731026d2..ae094397fa 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts @@ -1,7 +1,7 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import BigNumber from 'bignumber.js' import { Testing } from '@defichain/jellyfish-testing' -import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' +import { DfTxType, FutureSwap } from '../../../src/category/account' import { RpcApiError } from '@defichain/jellyfish-api-core' const container = new MasterNodeRegTestContainer() @@ -10,10 +10,7 @@ let collateralAddress: string let oracleId: string let idDUSD: string let idTSLA: string -// let idAMZN: string -// let idBTC: string const attributeKey = 'ATTRIBUTES' -// let key: string let futInterval: number let futRewardPercentage: number const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' @@ -93,9 +90,7 @@ async function setup (): Promise { }) await testing.generate(1) - // idBTC = await testing.token.getTokenId('BTC') idTSLA = await testing.token.getTokenId('TSLA') - // idAMZN = await testing.token.getTokenId('AMZN') idDUSD = await testing.token.getTokenId('DUSD') // create a vault and take loans @@ -211,10 +206,11 @@ describe('futureSwap', () => { const nextSettleBlock = await getNextSettleBlock() await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + let mintedDUSD: BigNumber // check future settled { // calclulate minted DUSD. dtoken goes for a discount. - const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; + mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) @@ -243,6 +239,10 @@ describe('futureSwap', () => { // check burn const burnAfter = await testing.rpc.account.getBurnInfo() expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) + + // check results can be retrived via account history + const accountHistories = await testing.rpc.account.listAccountHistory('all', { txtype: DfTxType.FUTURE_SWAP_EXECUTION }) + expect(accountHistories[0]).toStrictEqual(expect.objectContaining({ owner: tslaAddress, type: 'FutureSwapExecution', amounts: [mintedDUSD.toFixed(8) + '@DUSD'] })) }) it('should create futureswap dtoken to dusd just before the next settle block', async () => { @@ -469,6 +469,11 @@ describe('futureSwap', () => { // check burn const burnAfter = await testing.rpc.account.getBurnInfo() expect(burnAfter.dfip2203).toStrictEqual([]) + + // check results can be retrived via account history + const accountHistories = await testing.rpc.account.listAccountHistory('all', { txtype: DfTxType.FUTURE_SWAP_REFUND }) + expect(accountHistories[0]).toStrictEqual(expect.objectContaining({ owner: contractAddress, type: 'FutureSwapRefund', amounts: ['-' + swapAmount.toFixed(8) + '@TSLA'] })) + expect(accountHistories[1]).toStrictEqual(expect.objectContaining({ owner: tslaAddress, type: 'FutureSwapRefund', amounts: [swapAmount.toFixed(8) + '@TSLA'] })) }) it('should create futureswap dusd to dtoken', async () => { @@ -679,6 +684,16 @@ describe('futureSwap', () => { await expect(promise).rejects.toThrow(RpcApiError) await expect(promise).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: futureswap') } + { + // non loan source token + const fswap: FutureSwap = { + address: tslaAddress, + amount: '1@BTC' + } + const promise = testing.rpc.account.futureSwap(fswap) + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get source loan token 1\', code: -32600, method: futureswap') + } { // destination is given when futureswap dtoken to dusd const fswap: FutureSwap = { diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 41cb2e7f3f..0068d95d4a 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -29,7 +29,9 @@ export enum DfTxType { UPDATE_POOL_PAIR = 'u', SET_GOV_VARIABLE = 'G', AUTO_AUTH_PREP = 'A', - NONE = '0' + NONE = '0', + FUTURE_SWAP_EXECUTION = 'q', + FUTURE_SWAP_REFUND = 'w' } export enum SelectionModeType { From 703243a1e9f6aa09f01ae5c2a221c71d14ac3234 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 5 Apr 2022 20:27:06 +0800 Subject: [PATCH 18/32] Removed untested futureswap extra APIs. --- docs/node/CATEGORIES/08-account.md | 58 ------------------ docs/node/CATEGORIES/09-oracle.md | 10 ---- .../src/category/account.ts | 59 ------------------- .../jellyfish-api-core/src/category/oracle.ts | 9 --- 4 files changed, 136 deletions(-) diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index ab7b617fcb..42e9bd3a34 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -490,62 +490,4 @@ interface UTXO { txid: string vout: number } -``` - -## withdrawFutureSwap - -Creates and submits to the network a withdrawl from futures contract transaction. - -```ts title="client.account.withdrawFutureSwap()" -interface account { - withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise -} - -interface FutureSwap { - address: string - amount: string - destination?: string -} - -interface UTXO { - txid: string - vout: number -} -``` - -## listPendingFutureSwaps - -List all pending futures. - -```ts title="client.account.listPendingFutureSwaps()" -interface account { - listPendingFutureSwaps (): Promise -} - -interface FutureInfo { - owner: string - source: string - destination: string -} -``` - -## getPendingFutureSwaps - -Get specific pending futures. - -```ts title="client.account.getPendingFutureSwaps()" -interface account { - getPendingFutureSwaps (): Promise -} - -interface GetFutureInfo { - owner: string - values: Omit [] -} - -interface FutureInfo { - owner: string - source: string - destination: string -} ``` \ No newline at end of file diff --git a/docs/node/CATEGORIES/09-oracle.md b/docs/node/CATEGORIES/09-oracle.md index 7f6c49f7aa..a1d5331147 100644 --- a/docs/node/CATEGORIES/09-oracle.md +++ b/docs/node/CATEGORIES/09-oracle.md @@ -249,14 +249,4 @@ interface ListFixedIntervalPrice { timestamp: number isLive: boolean } -``` - -## getFutureSwapBlock - -Get the next block that futures will execute and update on. - -```ts title="client.oracle.getFutureSwapBlock()" -interface oracle { - getFutureSwapBlock (): Promise -} ``` \ No newline at end of file diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 0068d95d4a..1404014d2f 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -406,40 +406,6 @@ export class Account { async futureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { return await this.client.call('futureswap', [future.address, future.amount, future.destination, utxos], 'number') } - - /** - * Creates and submits to the network a withdrawl from futures contract transaction. - * - * @param {FutureSwap} future - * @param {string} future.address Address to fund contract and receive resulting token - * @param {string} future.amount Amount to send in amount@token format - * @param {string} [future.destination] Expected dToken if DUSD supplied - * @param {UTXO[]} [options.utxos = []] - * @param {string} options.utxos.txid - * @param {number} options.utxos.vout - * @return {Promise} - */ - async withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise { - return await this.client.call('withdrawfutureswap', [future, utxos], 'number') - } - - /** - * List all pending futures. - * - * @return {Promise} - */ - async listPendingFutureSwaps (): Promise { - return await this.client.call('listpendingfutureswaps', [], 'number') - } - - /** - * Get specific pending futures. - * - * @return {Promise} - */ - async getPendingFutureSwaps (): Promise { - return await this.client.call('getpendingfutureswaps', [], 'number') - } } export interface AccountPagination { @@ -614,28 +580,3 @@ export interface FutureSwap { amount: string destination?: string } - -export interface FutureInfo { - owner: string - source: string - destination: string -} - -export interface GetFutureInfo { - owner: string - values: Array> -} - -export interface ListFutureHistoryOptions { - maxBlockHeight: number - depth: number - token: string - limit: number -} - -export interface FutureHistory { - height: number - address: string - source: string - destination: string -} diff --git a/packages/jellyfish-api-core/src/category/oracle.ts b/packages/jellyfish-api-core/src/category/oracle.ts index 940c2f155b..be7cd24380 100644 --- a/packages/jellyfish-api-core/src/category/oracle.ts +++ b/packages/jellyfish-api-core/src/category/oracle.ts @@ -160,15 +160,6 @@ export class Oracle { nextPrice: 'bignumber' }) } - - /** - * Get the next block that futures will execute and update on. - * - * @return {Promise} - */ - async getFutureSwapBlock (): Promise { - return await this.client.call('getfutureswapblock', [], 'number') - } } export interface AppointOracleOptions { From e653cdce5a2e4d5c9b150ad5427357fd99ac9e9a Mon Sep 17 00:00:00 2001 From: websterlcl Date: Wed, 6 Apr 2022 12:58:25 +0800 Subject: [PATCH 19/32] fix pg as master-35ad71b82 require participate pool with liq --- .../modules/PlaygroundModule.test.ts | 16 +++--- apps/playground-api/src/setups/setup.dex.ts | 49 +++++++++++++++++-- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/apps/playground-api/__tests__/modules/PlaygroundModule.test.ts b/apps/playground-api/__tests__/modules/PlaygroundModule.test.ts index 59dfd64a61..d4d21f29fe 100644 --- a/apps/playground-api/__tests__/modules/PlaygroundModule.test.ts +++ b/apps/playground-api/__tests__/modules/PlaygroundModule.test.ts @@ -13,12 +13,12 @@ afterAll(async () => { it('should have pool pairs setup', async () => { const pairs = await testing.container.call('listpoolpairs') - expect(Object.values(pairs).length).toBe(12) + expect(Object.values(pairs).length).toBe(14) }) it('should have tokens setup', async () => { const tokens = await testing.container.call('listtokens') - expect(Object.values(tokens).length).toBe(29) + expect(Object.values(tokens).length).toBe(31) }) it('should have oracles setup', async () => { @@ -116,10 +116,14 @@ it('should have gov set', async () => { }) await testing.generate(1) - await testing.container.waitForPriceValid('TD10/USD') - await testing.container.waitForPriceValid('TU10/USD') - await testing.container.waitForPriceValid('TR50/USD') - await testing.container.waitForPriceValid('TS25/USD') + { + const prices = await testing.container.call('listfixedintervalprices') + + const invalidPrices = prices.filter((p: any) => p.isLive !== true) + for (const p of invalidPrices) { + await testing.container.waitForPriceValid(p.priceFeedId) + } + } await testing.rpc.loan.takeLoan({ vaultId: vaultId, diff --git a/apps/playground-api/src/setups/setup.dex.ts b/apps/playground-api/src/setups/setup.dex.ts index 927a7cbbb3..0748fe4be9 100644 --- a/apps/playground-api/src/setups/setup.dex.ts +++ b/apps/playground-api/src/setups/setup.dex.ts @@ -104,6 +104,12 @@ export class SetupDex extends PlaygroundSetup { commission: 0.02, status: true, ownerAddress: PlaygroundSetup.address + }, + add: { + '*': ['10000000@DUSD', '10000000@DFI'] + }, + utxoToAccount: { + [PlaygroundSetup.address]: '10000000@0' } }, { @@ -114,6 +120,9 @@ export class SetupDex extends PlaygroundSetup { commission: 0.02, status: true, ownerAddress: PlaygroundSetup.address + }, + add: { + '*': ['10000000@DUSD', '10000000@TU10'] } }, { @@ -124,6 +133,9 @@ export class SetupDex extends PlaygroundSetup { commission: 0.02, status: true, ownerAddress: PlaygroundSetup.address + }, + add: { + '*': ['10000000@DUSD', '10000000@TD10'] } }, { @@ -144,6 +156,9 @@ export class SetupDex extends PlaygroundSetup { commission: 0.02, status: true, ownerAddress: PlaygroundSetup.address + }, + add: { + '*': ['10000000@DUSD', '10000000@TR50'] } }, { @@ -165,6 +180,32 @@ export class SetupDex extends PlaygroundSetup { status: false, ownerAddress: PlaygroundSetup.address } + }, + { + symbol: 'BTC-DUSD', + create: { + tokenA: 'BTC', + tokenB: 'DUSD', + commission: 0.01, + status: true, + ownerAddress: PlaygroundSetup.address + }, + add: { + '*': ['1000@BTC', '10000000@DUSD'] + } + }, + { + symbol: 'CU10-DUSD', + create: { + tokenA: 'CU10', + tokenB: 'DUSD', + commission: 0.01, + status: true, + ownerAddress: PlaygroundSetup.address + }, + add: { + '*': ['100000@CU10', '1000@DUSD'] + } } ] } @@ -199,7 +240,7 @@ export class SetupDex extends PlaygroundSetup { const poolPairs = await this.client.poolpair.listPoolPairs() const poolPairIds = Object.keys(poolPairs) - // apply `toFixed(8)` due to 1 / 12 = 0.08333333333333333 which is invalid amount on setgov + // apply `toFixed(8)` due to 1 / 14 = 0.07142857 which is invalid amount on setgov const splits = Number(new BigNumber(1 / poolPairIds.length).toFixed(8)) const lpSplits: any = {} @@ -207,10 +248,10 @@ export class SetupDex extends PlaygroundSetup { lpSplits[parseInt(k)] = splits } - // to fix: LP_SPLITS: total = 99999996 vs expected 100000000', code: -32600, method: setgov - // 0.08333333 * 11 !== 100000000 + // to fix: LP_SPLITS: total = 99999998 vs expected 100000000', code: -32600, method: setgov + // 0.07142857 * 14 !== 100000000 const lstKey = Object.keys(lpSplits)[0] - lpSplits[lstKey] = Number(new BigNumber(lpSplits[lstKey]).plus(0.00000004).toFixed(8)) + lpSplits[lstKey] = Number(new BigNumber(lpSplits[lstKey]).plus(0.00000002).toFixed(8)) await this.client.masternode.setGov({ LP_SPLITS: lpSplits }) await this.generate(1) From ca22ab22a7730308a8e9dd1c882bd6dacbe9cc62 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Wed, 6 Apr 2022 10:47:33 +0530 Subject: [PATCH 20/32] Added withdraw future swap fail test cases --- .../account/withdrawFutureSwap.test.ts | 189 +++++++++++++++++- 1 file changed, 179 insertions(+), 10 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 5875341eec..b973bf01a2 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -2,17 +2,13 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import BigNumber from 'bignumber.js' import { Testing } from '@defichain/jellyfish-testing' import { FutureSwap } from 'packages/jellyfish-api-core/src/category/account' +import { RpcApiError } from '@defichain/jellyfish-api-core' const container = new MasterNodeRegTestContainer() const testing = Testing.create(container) let collateralAddress: string let oracleId: string -// let idDUSD: string -// let idTSLA: string -// let idAMZN: string -// let idBTC: string const attributeKey = 'ATTRIBUTES' -// let key: string let futInterval: number let futRewardPercentage: number const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' @@ -92,11 +88,6 @@ async function setup (): Promise { }) await testing.generate(1) - // idBTC = await testing.token.getTokenId('BTC') - idTSLA = await testing.token.getTokenId('TSLA') - // idAMZN = await testing.token.getTokenId('AMZN') - idDUSD = await testing.token.getTokenId('DUSD') - // create a vault and take loans const vaultAddr = await testing.generateAddress() const vaultId = await testing.rpc.loan.createVault({ @@ -360,4 +351,182 @@ describe('withdrawFutureSwap', () => { const nextSettleBlock = await getNextSettleBlock() expect(currentBlock).toBeLessThan(nextSettleBlock) }) + + it('should not withdraw invalid futureswap dtoken to dusd - before settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // Withdraw fail - Destination should not be set when source amount is a dToken + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@TSLA', + destination: 'DUSD' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDestination should not be set when source amount is a dToken\', code: -32600, method: withdrawfutureswap') + } + + // Withdraw fail - amount 0.00000000 is less than 0.50000000 + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@DUSD', + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + } + + // Withdraw fail - Invalid Defi token: NANA + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@NANA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: NANA\', code: 0, method: withdrawfutureswap') + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await getNextSettleBlock() + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + + it('should not withdraw invalid futureswap dusd to dtoken - before settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // Withdraw fail - Could not get destination loan token 0. Set valid destination + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@DUSD' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get destination loan token 0. Set valid destination.\', code: -32600, method: withdrawfutureswap') + } + + // Withdraw fail - amount 0.00000000 is less than 0.50000000 + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + } + + // Withdraw fail - Invalid Defi token: NANA + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@NANA', + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: NANA\', code: 0, method: withdrawfutureswap') + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await getNextSettleBlock() + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + + it('should not withdraw futureswap dtoken to dusd - after settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // move to next settle block + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + const withdrawAmount = swapAmount / 2 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@TSLA' + } + + // withdraw half of the future swap + { + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + } + }) + + it('should not withdraw futureswap dusd to dtoken - after settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const swapAmount = 1 + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // move to next settle block + const nextSettleBlock = await getNextSettleBlock() + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + + const withdrawAmount = swapAmount / 2 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@DUSD', + destination: 'TSLA' + } + + // withdraw half of the future swap + { + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + } + }) }) From cfd7852812e7e78a4cb5e3e41bdc52e485b9a531 Mon Sep 17 00:00:00 2001 From: surangap Date: Wed, 6 Apr 2022 14:40:10 +0800 Subject: [PATCH 21/32] Fixed failing test due to ain 1159. --- .../txn/txn_builder_loan_payback_loan.test.ts | 158 +++++++++++++++++- 1 file changed, 150 insertions(+), 8 deletions(-) diff --git a/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts b/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts index 6be3618ead..cd07b5afa5 100644 --- a/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts +++ b/packages/jellyfish-transaction-builder/__tests__/txn/txn_builder_loan_payback_loan.test.ts @@ -872,7 +872,7 @@ describe('paybackLoan for any token', () => { const container = new MasterNodeRegTestContainer() const testing = Testing.create(container) - const dusdLoanAmount = 5000 + const dusdLoanAmount = 50000 const tslaLoanAmount = 10 const loanSchemeId = 'scheme' const attributeKey = 'ATTRIBUTES' @@ -1250,7 +1250,11 @@ describe('paybackLoan for any token', () => { const dfiPaybackAmount = dusdLoanAmount + 1000 const defaultPenaltyRate = 0.01 const dfiEffectPriceAfterPenaltyRate = 1 * (1 - defaultPenaltyRate) - const dfiNeededToPayOffDusd = dusdLoanAmountBefore.dividedBy(dfiEffectPriceAfterPenaltyRate).decimalPlaces(8, BigNumber.ROUND_CEIL) + let dfiNeededToPayOffDusd = dusdLoanAmountBefore.dividedBy(dfiEffectPriceAfterPenaltyRate) + + if (dfiNeededToPayOffDusd.multipliedBy(dfiEffectPriceAfterPenaltyRate) !== dusdLoanAmountBefore) { + dfiNeededToPayOffDusd = dfiNeededToPayOffDusd.plus(0.00000001) + } const colScript = P2WPKH.fromAddress(RegTest, vaultOwnerAddress, P2WPKH).getScript() const script = await testingProvider.elliptic.script() @@ -1269,7 +1273,7 @@ describe('paybackLoan for any token', () => { const totalDfiPenalty = dfiNeededToPayOffDusd.multipliedBy(defaultPenaltyRate) const totalDusdPaybackAmount = dusdLoanAmountBefore const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.paybackburn.toFixed(8)).toStrictEqual(totalDusdPaybackAmount.plus(totalDfiPenalty).toFixed(8)) + expect(burnInfoAfter.paybackburn.toFixed(8)).toStrictEqual(dfiNeededToPayOffDusd.toFixed(8)) expect(burnInfoAfter.dfipaybackfee.toFixed(8)).toStrictEqual(totalDfiPenalty.toFixed(8, BigNumber.ROUND_FLOOR)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${totalDusdPaybackAmount.toFixed(8)}@DUSD`]) @@ -1345,6 +1349,37 @@ describe('paybackLoan for any token', () => { it('should be able to payback DUSD loan using TSLA - use PaybackLoanMetadataV2', async () => { await takeTslaTokensToPayback() + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-TSLA + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'TSLA' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-TSLA + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20 }, + b: { symbol: 'TSLA', amount: 10 } + }) + await testing.generate(1) + } + const dusdInfo = await testing.rpc.token.getToken('DUSD') const dusdId: string = Object.keys(dusdInfo)[0] const tslaInfo = await testing.rpc.token.getToken('TSLA') @@ -1399,7 +1434,7 @@ describe('paybackLoan for any token', () => { const totalTslaPenalty = new BigNumber(tslaPaybackAmount).multipliedBy(penaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(tslaPaybackAmount).toFixed(8)}@TSLA`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${totalTslaPenalty.toFixed(8)}@TSLA`]) expect(burnInfoAfter.paybacktokens).toStrictEqual([`${dusdPayback.toFixed(8)}@DUSD`]) @@ -1415,6 +1450,37 @@ describe('paybackLoan for any token', () => { it('should be able to payback DUSD loan using both TSLA and DFI - use PaybackLoanMetadataV2', async () => { await takeTslaTokensToPayback() + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-TSLA + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'TSLA' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-TSLA + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20 }, + b: { symbol: 'TSLA', amount: 10 } + }) + await testing.generate(1) + } + const dfiInfo = await testing.rpc.token.getToken('DFI') const dfiId: string = Object.keys(dfiInfo)[0] const dusdInfo = await testing.rpc.token.getToken('DUSD') @@ -1484,7 +1550,7 @@ describe('paybackLoan for any token', () => { const totalDfiPenalty = new BigNumber(dfiPaybackAmount).multipliedBy(dfiPenaltyRate) const totalTslaPenalty = new BigNumber(tslaPaybackAmount).multipliedBy(tslaPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount).toFixed(8)}@DFI`, `${new BigNumber(tslaPaybackAmount).toFixed(8)}@TSLA`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(totalDfiPenalty) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${dusdPaybackByDfi.toFixed(8)}@DUSD`]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${totalTslaPenalty.toFixed(8)}@TSLA`]) @@ -1523,6 +1589,51 @@ describe('paybackLoan for any token', () => { }) await testing.generate(1) + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-TSLA + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'TSLA' + }) + await testing.generate(1) + + // create DUSD-BTC + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'BTC' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-TSLA + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20 }, + b: { symbol: 'TSLA', amount: 10 } + }) + await testing.generate(1) + + // add DUSD-BTC + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20000 }, + b: { symbol: 'BTC', amount: 2 } + }) + await testing.generate(1) + } + const dusdInfo = await testing.rpc.token.getToken('DUSD') const dusdId: string = Object.keys(dusdInfo)[0] const tslaInfo = await testing.rpc.token.getToken('TSLA') @@ -1592,7 +1703,7 @@ describe('paybackLoan for any token', () => { const totalTslaPenalty = new BigNumber(tslaPaybackAmount).multipliedBy(tslaPenaltyRate) const totalBtcPenalty = new BigNumber(btcPaybackAmount).multipliedBy(btcPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(tslaPaybackAmount).toFixed(8)}@TSLA`, `${new BigNumber(btcPaybackAmount).toFixed(8)}@BTC`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(new BigNumber(0)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${totalTslaPenalty.toFixed(8)}@TSLA`, `${totalBtcPenalty.toFixed(8)}@BTC`]) @@ -1726,7 +1837,7 @@ describe('paybackLoan for any token', () => { const totalDfiPenalty = new BigNumber(dfiPaybackAmount).multipliedBy(penaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(dfiPaybackAmount).toFixed(8)}@DFI`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(totalDfiPenalty) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([`${tslaPayback.toFixed(8)}@TSLA`]) @@ -1853,6 +1964,37 @@ describe('paybackLoan for any token', () => { }) await testing.generate(1) + // create pools required for SwapToDFIOverUSD burn + { + // create DUSD-DFI + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'DFI' + }) + await testing.generate(1) + + // create DUSD-BTC + await testing.poolpair.create({ + tokenA: 'DUSD', + tokenB: 'BTC' + }) + await testing.generate(1) + + // add DUSD-DFI + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 1000 }, + b: { symbol: 'DFI', amount: 1000 } + }) + await testing.generate(1) + + // add DUSD-BTC + await testing.poolpair.add({ + a: { symbol: 'DUSD', amount: 20000 }, + b: { symbol: 'BTC', amount: 2 } + }) + await testing.generate(1) + } + const tslaTakeLoanBlockHeight = await testing.rpc.blockchain.getBlockCount() await testing.rpc.loan.takeLoan({ vaultId: vaultId, @@ -1935,7 +2077,7 @@ describe('paybackLoan for any token', () => { const btcPenaltyForTslaLoan = new BigNumber(btcPaybackAmount).multipliedBy(tslaPenaltyRate) const burnInfoAfter = await testing.rpc.account.getBurnInfo() - expect(burnInfoAfter.tokens).toStrictEqual([`${new BigNumber(btcPaybackAmount * 2).toFixed(8)}@BTC`]) + expect(burnInfoAfter.tokens).toStrictEqual([]) expect(burnInfoAfter.dfipaybackfee).toStrictEqual(new BigNumber(0)) expect(burnInfoAfter.dfipaybacktokens).toStrictEqual([]) expect(burnInfoAfter.paybackfees).toStrictEqual([`${btcPenaltyForDusdLoan.plus(btcPenaltyForTslaLoan).toFixed(8)}@BTC`]) From deaffcd91215017ca34cdbb0eebf851312ee1e74 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Wed, 6 Apr 2022 14:44:29 +0530 Subject: [PATCH 22/32] Added tests to withdraw 1 satoshi of future amount --- .../account/withdrawFutureSwap.test.ts | 160 +++++++++++++++++- 1 file changed, 154 insertions(+), 6 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index b973bf01a2..9c6da82fd6 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -12,6 +12,7 @@ const attributeKey = 'ATTRIBUTES' let futInterval: number let futRewardPercentage: number const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' +const swapAmount = 1 async function setup (): Promise { collateralAddress = await testing.generateAddress() @@ -155,7 +156,6 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) await testing.generate(1) - const swapAmount = 1 const fswap: FutureSwap = { address: tslaAddress, amount: swapAmount.toString() + '@TSLA' @@ -255,7 +255,6 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) await testing.generate(1) - const swapAmount = 1 const fswap: FutureSwap = { address: tslaAddress, amount: swapAmount.toString() + '@DUSD', @@ -352,12 +351,139 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) + it('should withdraw 1 satoshi futureswap dtoken to dusd - before settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const withdrawAmount = 0.00000001 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@TSLA' + } + + // withdraw half of the future swap + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after withdrawing 1 satoshi + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@TSLA') + expect(pendingFutures[0].destination).toStrictEqual('DUSD') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@TSLA']) + } + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await getNextSettleBlock() + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + + it('should withdraw 1 satoshi futureswap dusd to dtoken - before settle block', async () => { + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: swapAmount.toString() + '@DUSD', + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const withdrawAmount = 0.00000001 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@DUSD', + destination: 'TSLA' + } + + // withdraw 1 satoshi of the future swap + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after withdrawing 1 satoshi + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@DUSD') + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@DUSD']) + } + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await getNextSettleBlock() + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + it('should not withdraw invalid futureswap dtoken to dusd - before settle block', async () => { const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) await testing.generate(1) - const swapAmount = 1 const fswap: FutureSwap = { address: tslaAddress, amount: swapAmount.toString() + '@TSLA' @@ -365,6 +491,18 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.futureSwap(fswap) await testing.generate(1) + // withdraw more than the future swap amount + { + const withdrawAmount = swapAmount + 0.00000001 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 1.00000000 is less than 1.00000001\', code: -32600, method: withdrawfutureswap') + } + // Withdraw fail - Destination should not be set when source amount is a dToken { const withdrawAmount = 0.5 @@ -414,7 +552,6 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) await testing.generate(1) - const swapAmount = 1 const fswap: FutureSwap = { address: tslaAddress, amount: swapAmount.toString() + '@DUSD', @@ -423,6 +560,19 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.futureSwap(fswap) await testing.generate(1) + // withdraw more than the future swap amount + { + const withdrawAmount = swapAmount + 0.00000001 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: withdrawAmount.toString() + '@DUSD', + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 1.00000000 is less than 1.00000001\', code: -32600, method: withdrawfutureswap') + } + // Withdraw fail - Could not get destination loan token 0. Set valid destination { const withdrawAmount = 0.5 @@ -471,7 +621,6 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) await testing.generate(1) - const swapAmount = 1 const fswap: FutureSwap = { address: tslaAddress, amount: swapAmount.toString() + '@TSLA' @@ -502,7 +651,6 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) await testing.generate(1) - const swapAmount = 1 const fswap: FutureSwap = { address: tslaAddress, amount: swapAmount.toString() + '@DUSD', From 267c4d571c7f7aca6a78f0eeae47fbd9e1596357 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Wed, 6 Apr 2022 17:32:03 +0530 Subject: [PATCH 23/32] Removed unwanted codes for this pr --- docs/node/CATEGORIES/08-account.md | 21 + .../category/account/futureswap.test.ts | 744 ------------------ .../account/withdrawFutureSwap.test.ts | 10 +- .../src/category/account.ts | 2 +- packages/jellyfish-testing/src/token.ts | 5 - .../containers/RegTestContainer/Masternode.ts | 24 - 6 files changed, 23 insertions(+), 783 deletions(-) delete mode 100644 packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts diff --git a/docs/node/CATEGORIES/08-account.md b/docs/node/CATEGORIES/08-account.md index 42e9bd3a34..6061a47859 100644 --- a/docs/node/CATEGORIES/08-account.md +++ b/docs/node/CATEGORIES/08-account.md @@ -486,6 +486,27 @@ interface FutureSwap { destination?: string } +interface UTXO { + txid: string + vout: number +} +``` + +## withdrawFutureSwap + +Creates and submits to the network a withdrawal from futures contract transaction. + +```ts title="client.account.withdrawFutureSwap()" +interface account { + withdrawFutureSwap (future: FutureSwap, utxos: UTXO[] = []): Promise +} + +interface FutureSwap { + address: string + amount: string + destination?: string +} + interface UTXO { txid: string vout: number diff --git a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts deleted file mode 100644 index ae094397fa..0000000000 --- a/packages/jellyfish-api-core/__tests__/category/account/futureswap.test.ts +++ /dev/null @@ -1,744 +0,0 @@ -import { MasterNodeRegTestContainer } from '@defichain/testcontainers' -import BigNumber from 'bignumber.js' -import { Testing } from '@defichain/jellyfish-testing' -import { DfTxType, FutureSwap } from '../../../src/category/account' -import { RpcApiError } from '@defichain/jellyfish-api-core' - -const container = new MasterNodeRegTestContainer() -const testing = Testing.create(container) -let collateralAddress: string -let oracleId: string -let idDUSD: string -let idTSLA: string -const attributeKey = 'ATTRIBUTES' -let futInterval: number -let futRewardPercentage: number -const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' - -async function setup (): Promise { - collateralAddress = await testing.generateAddress() - await testing.token.dfi({ address: collateralAddress, amount: 300000 }) - await testing.token.create({ symbol: 'BTC', collateralAddress }) - await testing.generate(1) - await testing.token.mint({ symbol: 'BTC', amount: 20000 }) - await testing.generate(1) - - // loan scheme - await testing.container.call('createloanscheme', [100, 1, 'default']) - await testing.generate(1) - - // price oracle - const priceFeeds = [ - { token: 'DFI', currency: 'USD' }, - { token: 'BTC', currency: 'USD' }, - { token: 'TSLA', currency: 'USD' }, - { token: 'AMZN', currency: 'USD' }, - { token: 'DUSD', currency: 'USD' } - ] - - const addr = await testing.generateAddress() - oracleId = await testing.rpc.oracle.appointOracle(addr, priceFeeds, { weightage: 1 }) - await testing.generate(1) - - const timestamp = Math.floor(new Date().getTime() / 1000) - await testing.rpc.oracle.setOracleData( - oracleId, - timestamp, - { - prices: [ - { tokenAmount: '1@DFI', currency: 'USD' }, - { tokenAmount: '10000@BTC', currency: 'USD' }, - { tokenAmount: '2@TSLA', currency: 'USD' }, - { tokenAmount: '4@AMZN', currency: 'USD' }, - { tokenAmount: '1@DUSD', currency: 'USD' } - ] - } - ) - await testing.generate(1) - - // collateral tokens - await testing.rpc.loan.setCollateralToken({ - token: 'DFI', - factor: new BigNumber(1), - fixedIntervalPriceId: 'DFI/USD' - }) - await testing.generate(1) - - await testing.rpc.loan.setCollateralToken({ - token: 'BTC', - factor: new BigNumber(0.5), - fixedIntervalPriceId: 'BTC/USD' - }) - await testing.generate(1) - - // loan token - await testing.rpc.loan.setLoanToken({ - symbol: 'TSLA', - fixedIntervalPriceId: 'TSLA/USD' - }) - await testing.generate(1) - - await testing.rpc.loan.setLoanToken({ - symbol: 'AMZN', - fixedIntervalPriceId: 'AMZN/USD' - }) - await testing.generate(1) - - await testing.rpc.loan.setLoanToken({ - symbol: 'DUSD', - fixedIntervalPriceId: 'DUSD/USD' - }) - await testing.generate(1) - - idTSLA = await testing.token.getTokenId('TSLA') - idDUSD = await testing.token.getTokenId('DUSD') - - // create a vault and take loans - const vaultAddr = await testing.generateAddress() - const vaultId = await testing.rpc.loan.createVault({ - ownerAddress: vaultAddr, - loanSchemeId: 'default' - }) - await testing.generate(1) - - await testing.rpc.loan.depositToVault({ - vaultId: vaultId, from: collateralAddress, amount: '100000@DFI' - }) - - // wait till the price valid. - await testing.container.waitForPriceValid('TSLA/USD') - - // take multiple loans - await testing.rpc.loan.takeLoan({ - vaultId: vaultId, - to: collateralAddress, - amounts: ['300@TSLA', '500@DUSD', '100@AMZN'] - }) - await testing.generate(1) - - // Futures setup - // set the dfip2203/active to false - await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) - await testing.generate(1) - - // set dfip2203 params - futInterval = 25 - futRewardPercentage = 0.05 - await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': futRewardPercentage.toString(), 'v0/params/dfip2203/block_period': futInterval.toString() } }) - await testing.generate(1) - - // activat the dfip2203/active now - await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) - await testing.generate(1) - - // Retrive and verify gov vars - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('true') - expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(futRewardPercentage.toString()) - expect(attributes.ATTRIBUTES['v0/params/dfip2203/block_period']).toStrictEqual(futInterval.toString()) -} - -async function getNextSettleBlock (): Promise { - const blockCount = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = blockCount + (futInterval - (blockCount % futInterval)) - return nextSettleBlock -} - -describe('futureSwap', () => { - beforeEach(async () => { - await testing.container.start() - await testing.container.waitForWalletCoinbaseMaturity() - await setup() - }) - - afterEach(async () => { - await testing.container.stop() - }) - - it('should create futureswap dtoken to dusd', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@TSLA') - expect(pendingFutures[0].destination).toStrictEqual('DUSD') - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() - - // dfip2203 burn should be empty - const burnBefore = await testing.rpc.account.getBurnInfo() - expect(burnBefore.dfip2203).toStrictEqual([]) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([]) - } - } - - // get minted DUSD - const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - - // move to next settle block - const nextSettleBlock = await getNextSettleBlock() - await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) - - let mintedDUSD: BigNumber - // check future settled - { - // calclulate minted DUSD. dtoken goes for a discount. - mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; - const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) - - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) - } - } - - // check burn - const burnAfter = await testing.rpc.account.getBurnInfo() - expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - - // check results can be retrived via account history - const accountHistories = await testing.rpc.account.listAccountHistory('all', { txtype: DfTxType.FUTURE_SWAP_EXECUTION }) - expect(accountHistories[0]).toStrictEqual(expect.objectContaining({ owner: tslaAddress, type: 'FutureSwapExecution', amounts: [mintedDUSD.toFixed(8) + '@DUSD'] })) - }) - - it('should create futureswap dtoken to dusd just before the next settle block', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - // move to next settle block - 1 - const nextSettleBlock = await getNextSettleBlock() - await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount() - 1) - - // get minted DUSD - const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // check future settled - { - // calclulate minted DUSD. dtoken goes for a discount. - const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; - const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) - - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) - } - } - - // check burn - const burnAfter = await testing.rpc.account.getBurnInfo() - expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - }) - - it('should consider new oracle active price, if changed before futureswap execution', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - let blockHeight = await testing.rpc.blockchain.getBlockCount() - let nextSettleBlock = await getNextSettleBlock() - - // move to next settle block for better duration for the oracle price to kick in - await testing.generate(nextSettleBlock - blockHeight) - blockHeight = await testing.rpc.blockchain.getBlockCount() - nextSettleBlock = await getNextSettleBlock() - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // change the oracle price - const timestamp = Math.floor(new Date().getTime() / 1000) - await testing.rpc.oracle.setOracleData( - oracleId, - timestamp, - { - prices: [ - { tokenAmount: '2.2@TSLA', currency: 'USD' } - ] - } - ) - await testing.generate(1) - await testing.container.waitForActivePrice('TSLA/USD', '2.2') - - const blockHeightAfter = await testing.rpc.blockchain.getBlockCount() - - // check next settle block is not reached yet - expect(blockHeightAfter).toBeLessThan(nextSettleBlock) - - // get minted DUSD - const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - - // move to nextSettleBlock - await testing.generate(nextSettleBlock - blockHeightAfter) - - // check future settled - { - // calclulate minted DUSD. dtoken goes for a discount. - const mintedDUSD = new BigNumber((1 - futRewardPercentage) * 2.2 * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1 - reward percentage) * TSLADUSD value * TSLA swap amount; - const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore.plus(mintedDUSD)) - - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([mintedDUSD.toFixed(8) + '@DUSD']) - } - } - - // check burn - const burnAfter = await testing.rpc.account.getBurnInfo() - expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - }) - - it('should refund if the oracle price is invalid at futureswap execution block', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - let blockHeight = await testing.rpc.blockchain.getBlockCount() - let nextSettleBlock = await getNextSettleBlock() - - // move to next settle block - await testing.generate(nextSettleBlock - blockHeight) - blockHeight = await testing.rpc.blockchain.getBlockCount() - nextSettleBlock = await getNextSettleBlock() - const nextPriceBlock = await testing.container.getImmediatePriceBlockBeforeBlock('TSLA/USD', nextSettleBlock) - - // create the futureswap - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // check the futureswap is in effect - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - - // move to nextPriceBlock - 1 - await testing.generate(nextPriceBlock - 1 - await testing.rpc.blockchain.getBlockCount()) - - // change the oracle price - const timestamp = Math.floor(new Date().getTime() / 1000) - await testing.rpc.oracle.setOracleData( - oracleId, - timestamp, - { - prices: [ - { tokenAmount: '3@TSLA', currency: 'USD' } - ] - } - ) - await testing.generate(1) - { - // now check the price invalid - const priceDataInvalid = await testing.rpc.oracle.getFixedIntervalPrice('TSLA/USD') - expect(priceDataInvalid.isLive).toBeFalsy() - } - - // get minted DUSD - const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - - // move to nextSettleBlock - await testing.generate(nextSettleBlock - nextPriceBlock) - - // check price is still invalid - { - const priceDataInvalid = await testing.rpc.oracle.getFixedIntervalPrice('TSLA/USD') - expect(priceDataInvalid.isLive).toBeFalsy() - } - - // check futureswap is not executed. - { - const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore) - - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([]) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - } - } - - // check burn - const burnAfter = await testing.rpc.account.getBurnInfo() - expect(burnAfter.dfip2203).toStrictEqual([]) - - // check results can be retrived via account history - const accountHistories = await testing.rpc.account.listAccountHistory('all', { txtype: DfTxType.FUTURE_SWAP_REFUND }) - expect(accountHistories[0]).toStrictEqual(expect.objectContaining({ owner: contractAddress, type: 'FutureSwapRefund', amounts: ['-' + swapAmount.toFixed(8) + '@TSLA'] })) - expect(accountHistories[1]).toStrictEqual(expect.objectContaining({ owner: tslaAddress, type: 'FutureSwapRefund', amounts: [swapAmount.toFixed(8) + '@TSLA'] })) - }) - - it('should create futureswap dusd to dtoken', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) - await testing.generate(1) - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', - destination: 'TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(swapAmount.toFixed(8) + '@DUSD') - expect(pendingFutures[0].destination).toStrictEqual('TSLA') - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() - - // dfip2203 burn should be empty - const burnBefore = await testing.rpc.account.getBurnInfo() - expect(burnBefore.dfip2203).toStrictEqual([]) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([]) - } - } - - // get minted TSLA - const tslaMintedBefore = (await testing.rpc.token.getToken(idTSLA))[idTSLA].minted - - // move to next settle block - const nextSettleBlock = await getNextSettleBlock() - await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) - - // check future settled - { - // calclulate minted TSLA. dtoken goes for a premium. - const mintedTSLA = new BigNumber((1 / (1 + futRewardPercentage)) * (1 / 2) * swapAmount).dp(8, BigNumber.ROUND_FLOOR) // (1/(1 + reward percentage)) * (DUSDTSLA) value * DUSD swap amount; - const tslaMintedAfter = (await testing.rpc.token.getToken(idTSLA))[idTSLA].minted - expect(tslaMintedAfter).toStrictEqual(tslaMintedBefore.plus(mintedTSLA)) - - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([mintedTSLA.toString() + '@TSLA']) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([mintedTSLA.toString() + '@TSLA']) - } - } - - // check burn - const burnAfter = await testing.rpc.account.getBurnInfo() - expect(burnAfter.dfip2203).toStrictEqual([swapAmount.toFixed(8) + '@DUSD']) - }) - - it('should not create futureswap when DFIP2203 is not active', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - // deactivate DFIP2203 - await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) - await testing.generate(1) - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('false') - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - - const promise = testing.rpc.account.futureSwap(fswap) - - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDFIP2203 not currently active\', code: -32600, method: futureswap') - }) - - it('should refund the futureswap if DFIP2203 is disabled before execution', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - // create the futureswap - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - const nextSettleBlock = await getNextSettleBlock() - - // check the futureswap is in effect - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - - // get minted DUSD - const dusdMintedBefore = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - - // deactivate DFIP2203 - await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) - await testing.generate(1) - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('false') - - // move to nextSettleBlock - await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) - - // check futureswap is not executed. - { - const dusdMintedAfter = (await testing.rpc.token.getToken(idDUSD))[idDUSD].minted - expect(dusdMintedAfter).toStrictEqual(dusdMintedBefore) - - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([]) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([swapAmount.toFixed(8) + '@TSLA']) - } - } - - // check burn - const burnAfter = await testing.rpc.account.getBurnInfo() - expect(burnAfter.dfip2203).toStrictEqual([]) - }) - - it('should not create futureswap when invalid inputs given', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - { - // zero source amount is given - const fswap: FutureSwap = { - address: tslaAddress, - amount: '0@TSLA' - } - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: futureswap') - } - { - // negative source amount is given - const fswap: FutureSwap = { - address: tslaAddress, - amount: '-1@TSLA' - } - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: futureswap') - } - { - // invlaid source dtoken - const fswap: FutureSwap = { - address: tslaAddress, - amount: '1@INVALID' - } - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: futureswap') - } - { - // non loan source token - const fswap: FutureSwap = { - address: tslaAddress, - amount: '1@BTC' - } - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get source loan token 1\', code: -32600, method: futureswap') - } - { - // destination is given when futureswap dtoken to dusd - const fswap: FutureSwap = { - address: tslaAddress, - amount: '1@TSLA', - destination: 'DUSD' - } - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDestination should not be set when source amount is a dToken\', code: -32600, method: futureswap') - } - { - // INVALID destination is given when futureswap dusd to dtoken - const fswap: FutureSwap = { - address: tslaAddress, - amount: '1@DUSD', - destination: 'INVALID' - } - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \'Destination token not found\', code: -5, method: futureswap') - } - }) - - it('should not create futureswap when DFIP2203 is disabled for the dtoken', async () => { - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) - await testing.generate(1) - - // deactivate DFIP2203 for dtoken - const key = 'v0/token/' + idTSLA + '/dfip2203' - - await testing.rpc.masternode.setGov({ [attributeKey]: { [key]: 'false' } }) - await testing.generate(1) - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES[key]).toStrictEqual('false') - - const swapAmount = 1 - const fswap: FutureSwap = { - address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' - } - - const promise = testing.rpc.account.futureSwap(fswap) - await expect(promise).rejects.toThrow(RpcApiError) - await expect(promise).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDFIP2203 currently disabled for token 2\', code: -32600, method: futureswap') - }) -}) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 9c6da82fd6..3353d654c0 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -31,7 +31,6 @@ async function setup (): Promise { { token: 'DFI', currency: 'USD' }, { token: 'BTC', currency: 'USD' }, { token: 'TSLA', currency: 'USD' }, - { token: 'AMZN', currency: 'USD' }, { token: 'DUSD', currency: 'USD' } ] @@ -48,7 +47,6 @@ async function setup (): Promise { { tokenAmount: '1@DFI', currency: 'USD' }, { tokenAmount: '10000@BTC', currency: 'USD' }, { tokenAmount: '2@TSLA', currency: 'USD' }, - { tokenAmount: '4@AMZN', currency: 'USD' }, { tokenAmount: '1@DUSD', currency: 'USD' } ] } @@ -77,12 +75,6 @@ async function setup (): Promise { }) await testing.generate(1) - await testing.rpc.loan.setLoanToken({ - symbol: 'AMZN', - fixedIntervalPriceId: 'AMZN/USD' - }) - await testing.generate(1) - await testing.rpc.loan.setLoanToken({ symbol: 'DUSD', fixedIntervalPriceId: 'DUSD/USD' @@ -108,7 +100,7 @@ async function setup (): Promise { await testing.rpc.loan.takeLoan({ vaultId: vaultId, to: collateralAddress, - amounts: ['300@TSLA', '500@DUSD', '100@AMZN'] + amounts: ['300@TSLA', '500@DUSD'] }) await testing.generate(1) diff --git a/packages/jellyfish-api-core/src/category/account.ts b/packages/jellyfish-api-core/src/category/account.ts index 3ef82185e8..e2aa92fc7b 100644 --- a/packages/jellyfish-api-core/src/category/account.ts +++ b/packages/jellyfish-api-core/src/category/account.ts @@ -408,7 +408,7 @@ export class Account { } /** - * Creates and submits to the network a withdrawl from futures contract transaction. + * Creates and submits to the network a withdrawal from futures contract transaction. * * @param {FutureSwap} future * @param {string} future.address Address to fund contract and receive resulting token diff --git a/packages/jellyfish-testing/src/token.ts b/packages/jellyfish-testing/src/token.ts index 1a17fd84a7..76807f678b 100644 --- a/packages/jellyfish-testing/src/token.ts +++ b/packages/jellyfish-testing/src/token.ts @@ -43,11 +43,6 @@ export class TestingToken { const to = { [address]: [account] } return await this.rpc.account.sendTokensToAddress({}, to) } - - async getTokenId (symbol: string): Promise { - const tokenInfo = await this.rpc.token.getToken(symbol) - return Object.keys(tokenInfo)[0] - } } interface TestingTokenCreate { diff --git a/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts b/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts index 1a5f4dc2ec..78d71b6d03 100644 --- a/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts +++ b/packages/testcontainers/src/containers/RegTestContainer/Masternode.ts @@ -239,14 +239,6 @@ export class MasterNodeRegTestContainer extends RegTestContainer { }, timeout, 100, 'waitForPriceInvalid') } - /** - * Wait for valut state - * - * @param {string} vaultId - * @param {string} state - * @param {number} [timeout=30000] in ms - * @return {Promise} - */ async waitForVaultState (vaultId: string, state: string, timeout = 30000): Promise { return await waitForCondition(async () => { const vault = await this.call('getvault', [vaultId]) @@ -258,22 +250,6 @@ export class MasterNodeRegTestContainer extends RegTestContainer { }, timeout, 100, 'waitForVaultState') } - /** - * Get next price block before the given target block - * - * @param {string} fixedIntervalPriceId - * @param {number} [targetBlock] - * @return {Promise} - */ - async getImmediatePriceBlockBeforeBlock (fixedIntervalPriceId: string, targetBlock: number): Promise { - const data: any = await this.call('getfixedintervalprice', [fixedIntervalPriceId]) - let nextPriceBlock = data.nextPriceBlock as number - while (nextPriceBlock < targetBlock) { - nextPriceBlock += 6 // 1 hour in regtest is 6 blocks - } - return nextPriceBlock - } - /** * Wait for active price * From 9be53ef0affac0e711b6fd4778c435d7205d5937 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Wed, 6 Apr 2022 21:19:21 +0530 Subject: [PATCH 24/32] Added tests with utxo --- docs/node/CATEGORIES/09-oracle.md | 2 +- .../account/withdrawFutureSwap.test.ts | 266 +++++++++++++----- 2 files changed, 190 insertions(+), 78 deletions(-) diff --git a/docs/node/CATEGORIES/09-oracle.md b/docs/node/CATEGORIES/09-oracle.md index a1d5331147..4754a33c41 100644 --- a/docs/node/CATEGORIES/09-oracle.md +++ b/docs/node/CATEGORIES/09-oracle.md @@ -249,4 +249,4 @@ interface ListFixedIntervalPrice { timestamp: number isLive: boolean } -``` \ No newline at end of file +``` diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 3353d654c0..8d34ef3822 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -9,10 +9,9 @@ const testing = Testing.create(container) let collateralAddress: string let oracleId: string const attributeKey = 'ATTRIBUTES' -let futInterval: number -let futRewardPercentage: number +const futInterval = 25 +const futRewardPercentage = 0.05 const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' -const swapAmount = 1 async function setup (): Promise { collateralAddress = await testing.generateAddress() @@ -110,9 +109,7 @@ async function setup (): Promise { await testing.generate(1) // set dfip2203 params - futInterval = 25 - futRewardPercentage = 0.05 - await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': futRewardPercentage.toString(), 'v0/params/dfip2203/block_period': futInterval.toString() } }) + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': `${futRewardPercentage}`, 'v0/params/dfip2203/block_period': `${futInterval}` } }) await testing.generate(1) // activat the dfip2203/active now @@ -120,16 +117,10 @@ async function setup (): Promise { await testing.generate(1) // Retrive and verify gov vars - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + const attributes = await testing.rpc.masternode.getGov(attributeKey) expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('true') - expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(futRewardPercentage.toString()) - expect(attributes.ATTRIBUTES['v0/params/dfip2203/block_period']).toStrictEqual(futInterval.toString()) -} - -async function getNextSettleBlock (): Promise { - const blockCount = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = blockCount + (futInterval - (blockCount % futInterval)) - return nextSettleBlock + expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(`${futRewardPercentage}`) + expect(attributes.ATTRIBUTES['v0/params/dfip2203/block_period']).toStrictEqual(`${futInterval}`) } describe('withdrawFutureSwap', () => { @@ -144,13 +135,14 @@ describe('withdrawFutureSwap', () => { }) it('should withdraw futureswap dtoken to dusd - before settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' + amount: `${swapAmount.toFixed(8)}@TSLA` } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) @@ -158,7 +150,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = swapAmount / 2 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@TSLA' + amount: `${withdrawAmount.toFixed(8)}@TSLA` } // withdraw half of the future swap @@ -174,12 +166,12 @@ describe('withdrawFutureSwap', () => { const pendingFutures = await testing.container.call('listpendingfutureswaps') expect(pendingFutures.length).toStrictEqual(1) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@TSLA') + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`) expect(pendingFutures[0].destination).toStrictEqual('DUSD') // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -190,13 +182,13 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@TSLA']) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@TSLA`]) } } @@ -214,7 +206,7 @@ describe('withdrawFutureSwap', () => { expect(pendingFutures.length).toStrictEqual(0) // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + const attributes = await testing.rpc.masternode.getGov(attributeKey) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -232,24 +224,25 @@ describe('withdrawFutureSwap', () => { { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([(withdrawAmount * 2).toFixed(8) + '@TSLA']) + expect(balance).toStrictEqual([`${(withdrawAmount * 2).toFixed(8)}@TSLA`]) } } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) it('should withdraw futureswap dusd to dtoken - before settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } await testing.rpc.account.futureSwap(fswap) @@ -258,7 +251,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = swapAmount / 2 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@DUSD', + amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } @@ -275,12 +268,12 @@ describe('withdrawFutureSwap', () => { const pendingFutures = await testing.container.call('listpendingfutureswaps') expect(pendingFutures.length).toStrictEqual(1) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@DUSD') + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) expect(pendingFutures[0].destination).toStrictEqual('TSLA') // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -291,13 +284,13 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@DUSD']) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@DUSD`]) } } @@ -315,7 +308,7 @@ describe('withdrawFutureSwap', () => { expect(pendingFutures.length).toStrictEqual(0) // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') + const attributes = await testing.rpc.masternode.getGov(attributeKey) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -333,24 +326,25 @@ describe('withdrawFutureSwap', () => { { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([(withdrawAmount * 2).toFixed(8) + '@DUSD']) + expect(balance).toStrictEqual([`${(withdrawAmount * 2).toFixed(8)}@DUSD`]) } } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) it('should withdraw 1 satoshi futureswap dtoken to dusd - before settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' + amount: `${swapAmount.toFixed(8)}@TSLA` } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) @@ -358,7 +352,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.00000001 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@TSLA' + amount: `${withdrawAmount.toFixed(8)}@TSLA` } // withdraw half of the future swap @@ -374,12 +368,12 @@ describe('withdrawFutureSwap', () => { const pendingFutures = await testing.container.call('listpendingfutureswaps') expect(pendingFutures.length).toStrictEqual(1) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@TSLA') + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`) expect(pendingFutures[0].destination).toStrictEqual('DUSD') // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -390,30 +384,31 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@TSLA']) + expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@TSLA']) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@TSLA`]) } } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) it('should withdraw 1 satoshi futureswap dusd to dtoken - before settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } await testing.rpc.account.futureSwap(fswap) @@ -422,7 +417,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.00000001 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@DUSD', + amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } @@ -439,12 +434,12 @@ describe('withdrawFutureSwap', () => { const pendingFutures = await testing.container.call('listpendingfutureswaps') expect(pendingFutures.length).toStrictEqual(1) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual((swapAmount - withdrawAmount).toFixed(8) + '@DUSD') + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) expect(pendingFutures[0].destination).toStrictEqual('TSLA') // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov('ATTRIBUTES') - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -455,30 +450,144 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([(swapAmount - withdrawAmount).toFixed(8) + '@DUSD']) + expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([withdrawAmount.toFixed(8) + '@DUSD']) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@DUSD`]) } } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) + it('should withdraw futureswap dtoken to dusd with utxo', async () => { + const swapAmount = 1 + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount}@TSLA` + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const utxo = await testing.container.fundAddress(tslaAddress, 50) + + const txid = await testing.rpc.account.withdrawFutureSwap(fswap, [utxo]) + await testing.generate(1) + + const rawtx = await testing.container.call('getrawtransaction', [txid, true]) + expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) + expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${swapAmount.toFixed(8)}@TSLA`]) + } + } + }) + + it('should withdraw futureswap dusd to dtoken with utxo', async () => { + const swapAmount = 1 + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const utxo = await testing.container.fundAddress(tslaAddress, 50) + + const withdrawAmount = swapAmount / 2 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + + const txid = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) + await testing.generate(1) + + const rawtx = await testing.container.call('getrawtransaction', [txid, true]) + expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) + expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@DUSD`]) + } + } + }) + it('should not withdraw invalid futureswap dtoken to dusd - before settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' + amount: `${swapAmount.toFixed(8)}@TSLA` } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) @@ -488,7 +597,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = swapAmount + 0.00000001 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@TSLA' + amount: `${withdrawAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -500,7 +609,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@TSLA', + amount: `${withdrawAmount.toFixed(8)}@TSLA`, destination: 'DUSD' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -513,7 +622,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@DUSD', + amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -526,7 +635,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@NANA' + amount: `${withdrawAmount.toFixed(8)}@NANA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -535,18 +644,19 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) it('should not withdraw invalid futureswap dusd to dtoken - before settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } await testing.rpc.account.futureSwap(fswap) @@ -557,7 +667,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = swapAmount + 0.00000001 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@DUSD', + amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -570,7 +680,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@DUSD' + amount: `${withdrawAmount.toFixed(8)}@DUSD` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -582,7 +692,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@TSLA' + amount: `${withdrawAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -594,7 +704,7 @@ describe('withdrawFutureSwap', () => { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@NANA', + amount: `${withdrawAmount.toFixed(8)}@NANA`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -604,30 +714,31 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) it('should not withdraw futureswap dtoken to dusd - after settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@TSLA' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@TSLA' + amount: `${swapAmount.toFixed(8)}@TSLA` } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) // move to next settle block - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) const withdrawAmount = swapAmount / 2 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@TSLA' + amount: `${withdrawAmount.toFixed(8)}@TSLA` } // withdraw half of the future swap @@ -639,26 +750,27 @@ describe('withdrawFutureSwap', () => { }) it('should not withdraw futureswap dusd to dtoken - after settle block', async () => { + const swapAmount = 1 const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: '1@DUSD' }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: swapAmount.toString() + '@DUSD', + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) // move to next settle block - const nextSettleBlock = await getNextSettleBlock() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) const withdrawAmount = swapAmount / 2 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: withdrawAmount.toString() + '@DUSD', + amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } From d356563146077de0e58b7645e56f988bfe013d49 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Thu, 7 Apr 2022 12:15:13 +0530 Subject: [PATCH 25/32] Added tests according to review comments --- .../account/withdrawFutureSwap.test.ts | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 8d34ef3822..01d5cf0c09 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -336,6 +336,144 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) + it('should withdraw futureswaps dtoken to dusd - before settle block', async () => { + const swapAmount = 1 + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@TSLA` }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount.toFixed(8)}@TSLA` + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const withdrawAmount = swapAmount * 1.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + + // withdraw from both of the future swaps + { + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after withdrawing + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`) + expect(pendingFutures[0].destination).toStrictEqual('DUSD') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@TSLA`]) + } + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + + it('should withdraw futureswaps dusd to dtoken - before settle block', async () => { + const swapAmount = 1 + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@DUSD` }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const withdrawFutureSwap1: FutureSwap = { + address: tslaAddress, + amount: `${(swapAmount * 0.8).toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const withdrawFutureSwap2: FutureSwap = { + address: tslaAddress, + amount: `${(swapAmount * 1.2).toFixed(8)}@DUSD`, + destination: 'TSLA' + } + + // withdraw all within the same block + { + const result1 = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap1) + expect(typeof result1).toStrictEqual('string') + expect(result1.length).toStrictEqual(64) + const result2 = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap2) + expect(typeof result2).toStrictEqual('string') + expect(result2.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after withdrawing all + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${(swapAmount * 2).toFixed(8)}@DUSD`]) + } + } + + // verify that all happened before settle block + const currentBlock = await testing.rpc.blockchain.getBlockCount() + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) + expect(currentBlock).toBeLessThan(nextSettleBlock) + }) + it('should withdraw 1 satoshi futureswap dtoken to dusd - before settle block', async () => { const swapAmount = 1 const tslaAddress = await testing.generateAddress() From 3d6fcb03084cfb85dff867504f739bbd6dddadca Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Thu, 7 Apr 2022 23:27:19 +0530 Subject: [PATCH 26/32] Added/updated tests as per review comments --- .../account/withdrawFutureSwap.test.ts | 312 +++++++++++++++--- packages/jellyfish-testing/src/token.ts | 5 + 2 files changed, 276 insertions(+), 41 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 01d5cf0c09..5cbce19ae5 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -7,10 +7,7 @@ import { RpcApiError } from '@defichain/jellyfish-api-core' const container = new MasterNodeRegTestContainer() const testing = Testing.create(container) let collateralAddress: string -let oracleId: string const attributeKey = 'ATTRIBUTES' -const futInterval = 25 -const futRewardPercentage = 0.05 const contractAddress = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpsqgljc' async function setup (): Promise { @@ -34,7 +31,7 @@ async function setup (): Promise { ] const addr = await testing.generateAddress() - oracleId = await testing.rpc.oracle.appointOracle(addr, priceFeeds, { weightage: 1 }) + const oracleId = await testing.rpc.oracle.appointOracle(addr, priceFeeds, { weightage: 1 }) await testing.generate(1) const timestamp = Math.floor(new Date().getTime() / 1000) @@ -109,14 +106,16 @@ async function setup (): Promise { await testing.generate(1) // set dfip2203 params + const futInterval = 25 + const futRewardPercentage = 0.05 await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/reward_pct': `${futRewardPercentage}`, 'v0/params/dfip2203/block_period': `${futInterval}` } }) await testing.generate(1) - // activat the dfip2203/active now + // set the dfip2203/active to true await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) await testing.generate(1) - // Retrive and verify gov vars + // Retrieve and verify gov vars const attributes = await testing.rpc.masternode.getGov(attributeKey) expect(attributes.ATTRIBUTES['v0/params/dfip2203/active']).toStrictEqual('true') expect(attributes.ATTRIBUTES['v0/params/dfip2203/reward_pct']).toStrictEqual(`${futRewardPercentage}`) @@ -134,8 +133,9 @@ describe('withdrawFutureSwap', () => { await testing.container.stop() }) - it('should withdraw futureswap dtoken to dusd - before settle block', async () => { + it('Should withdrawFutureSwap futureswap dtoken to dusd', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) @@ -230,12 +230,12 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should withdraw futureswap dusd to dtoken - before settle block', async () => { + it('Should withdrawFutureSwap futureswap dusd to dtoken', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) @@ -332,12 +332,12 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should withdraw futureswaps dtoken to dusd - before settle block', async () => { + it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@TSLA` }) await testing.generate(1) @@ -398,12 +398,12 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should withdraw futureswaps dusd to dtoken - before settle block', async () => { + it('Should withdrawFutureSwap from multiple futureswaps dusd to dtoken', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@DUSD` }) await testing.generate(1) @@ -470,12 +470,12 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should withdraw 1 satoshi futureswap dtoken to dusd - before settle block', async () => { + it('Should withdrawFutureSwap 1 satoshi futureswap dtoken to dusd', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) @@ -493,7 +493,7 @@ describe('withdrawFutureSwap', () => { amount: `${withdrawAmount.toFixed(8)}@TSLA` } - // withdraw half of the future swap + // withdraw 1 satoshi { const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) expect(typeof result).toStrictEqual('string') @@ -534,12 +534,12 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should withdraw 1 satoshi futureswap dusd to dtoken - before settle block', async () => { + it('Should withdrawFutureSwap 1 satoshi futureswap dusd to dtoken', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) @@ -559,7 +559,7 @@ describe('withdrawFutureSwap', () => { destination: 'TSLA' } - // withdraw 1 satoshi of the future swap + // withdraw 1 satoshi { const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) expect(typeof result).toStrictEqual('string') @@ -600,11 +600,10 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should withdraw futureswap dtoken to dusd with utxo', async () => { + it('Should withdrawFutureSwap futureswap dtoken to dusd with utxo', async () => { const swapAmount = 1 const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) @@ -655,7 +654,7 @@ describe('withdrawFutureSwap', () => { } }) - it('should withdraw futureswap dusd to dtoken with utxo', async () => { + it('Should withdrawFutureSwap futureswap dusd to dtoken with utxo', async () => { const swapAmount = 1 const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) @@ -717,8 +716,9 @@ describe('withdrawFutureSwap', () => { } }) - it('should not withdraw invalid futureswap dtoken to dusd - before settle block', async () => { + it('Should not withdrawFutureSwap invalid futureswap dtoken to dusd', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) @@ -755,7 +755,7 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nDestination should not be set when source amount is a dToken\', code: -32600, method: withdrawfutureswap') } - // Withdraw fail - amount 0.00000000 is less than 0.50000000 + // Withdraw fail - try to withdraw from unavailable futureswap { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { @@ -768,26 +768,125 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') } - // Withdraw fail - Invalid Defi token: NANA + // Withdraw fail - Invalid Defi token: INVALID { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@NANA` + amount: `${withdrawAmount.toFixed(8)}@INVALID` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: withdrawfutureswap') + } + + // withdraw from arbitrary address + { + const withdrawAmount = swapAmount + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') + } + + // withdraw from arbitrary utxo + { + const withdrawAmount = swapAmount + const utxoAddress = await testing.generateAddress() + const utxo = await testing.container.fundAddress(utxoAddress, 50) + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nTransaction must have at least one input from owner\', code: -32600, method: withdrawfutureswap') + } + + // withdraw 0 amount + { + const withdrawAmount = 0 + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: NANA\', code: 0, method: withdrawfutureswap') + await expect(result).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: withdrawfutureswap') + } + + // withdraw -1 amount + { + const withdrawAmount = -1 + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: withdrawfutureswap') + } + + // withdraw 0.1 satoshi + { + const withdrawAmount = 0.000000001 + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: withdrawfutureswap') + } + + // withdraw after setting ${idTSLA}/dfip2203 to false + { + const idTSLA = await testing.token.getTokenId('TSLA') + await testing.rpc.masternode.setGov({ [attributeKey]: { [`v0/token/${idTSLA}/dfip2203`]: 'false' } }) + + const withdrawAmount = swapAmount + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'DFIP2203Tx: DFIP2203 currently disabled for token 2 (code 16)\', code: -26, method: withdrawfutureswap') + + await testing.rpc.masternode.setGov({ [attributeKey]: { [`v0/token/${idTSLA}/dfip2203`]: 'true' } }) + } + + // withdraw after setting the dfip2203/active to false + { + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + + const withdrawAmount = swapAmount + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'DFIP2203Tx: DFIP2203 not currently active (code 16)\', code: -26, method: withdrawfutureswap') + + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should not withdraw invalid futureswap dusd to dtoken - before settle block', async () => { + it('Should not withdrawFutureSwap invalid futureswap dusd to dtoken', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) @@ -813,7 +912,7 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 1.00000000 is less than 1.00000001\', code: -32600, method: withdrawfutureswap') } - // Withdraw fail - Could not get destination loan token 0. Set valid destination + // Withdraw fail - without valid destination { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { @@ -825,7 +924,7 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get destination loan token 0. Set valid destination.\', code: -32600, method: withdrawfutureswap') } - // Withdraw fail - amount 0.00000000 is less than 0.50000000 + // Withdraw fail - try to withdraw from unavailable futureswap { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { @@ -837,27 +936,133 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') } - // Withdraw fail - Invalid Defi token: NANA + // Withdraw fail - Invalid Defi token: INVALID { const withdrawAmount = 0.5 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@NANA`, + amount: `${withdrawAmount.toFixed(8)}@INVALID`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: withdrawfutureswap') + } + + // withdraw from arbitrary address + { + const withdrawAmount = swapAmount + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') + } + + // withdraw from arbitrary utxo + { + const withdrawAmount = swapAmount + const utxoAddress = await testing.generateAddress() + const utxo = await testing.container.fundAddress(utxoAddress, 50) + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nTransaction must have at least one input from owner\', code: -32600, method: withdrawfutureswap') + } + + // withdraw 0 amount + { + const withdrawAmount = 0 + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: withdrawfutureswap') + } + + // withdraw -1 amount + { + const withdrawAmount = -1 + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: withdrawfutureswap') + } + + // withdraw 0.1 satoshi + { + const withdrawAmount = 0.000000001 + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: NANA\', code: 0, method: withdrawfutureswap') + await expect(result).rejects.toThrow('RpcApiError: \': Amount out of range\', code: -3, method: withdrawfutureswap') + } + + // withdraw after setting ${idTSLA}/dfip2203 to false + { + const idTSLA = await testing.token.getTokenId('TSLA') + await testing.rpc.masternode.setGov({ [attributeKey]: { [`v0/token/${idTSLA}/dfip2203`]: 'false' } }) + + const withdrawAmount = swapAmount + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'DFIP2203Tx: DFIP2203 currently disabled for token 2 (code 16)\', code: -26, method: withdrawfutureswap') + + await testing.rpc.masternode.setGov({ [attributeKey]: { [`v0/token/${idTSLA}/dfip2203`]: 'true' } }) + } + + // withdraw after setting the dfip2203/active to false + { + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) + + const withdrawAmount = swapAmount + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'DFIP2203Tx: DFIP2203 not currently active (code 16)\', code: -26, method: withdrawfutureswap') + + await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'true' } }) } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('should not withdraw futureswap dtoken to dusd - after settle block', async () => { + it('Should not withdrawFutureSwap futureswap dtoken to dusd - at/after the settle block', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) @@ -870,7 +1075,6 @@ describe('withdrawFutureSwap', () => { await testing.generate(1) // move to next settle block - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) const withdrawAmount = swapAmount / 2 @@ -879,7 +1083,20 @@ describe('withdrawFutureSwap', () => { amount: `${withdrawAmount.toFixed(8)}@TSLA` } - // withdraw half of the future swap + // withdraw at the settle block + { + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + } + { + const result = testing.rpc.account.withdrawFutureSwap(fswap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') + } + + await testing.generate(1) + // withdraw after settle block { const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -887,8 +1104,9 @@ describe('withdrawFutureSwap', () => { } }) - it('should not withdraw futureswap dusd to dtoken - after settle block', async () => { + it('Should not withdrawFutureSwap futureswap dusd to dtoken - at/after the settle block', async () => { const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) await testing.generate(1) @@ -902,7 +1120,6 @@ describe('withdrawFutureSwap', () => { await testing.generate(1) // move to next settle block - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) const withdrawAmount = swapAmount / 2 @@ -912,7 +1129,20 @@ describe('withdrawFutureSwap', () => { destination: 'TSLA' } - // withdraw half of the future swap + // withdraw at the settle block + { + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + } + { + const result = testing.rpc.account.withdrawFutureSwap(fswap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') + } + + await testing.generate(1) + // withdraw after settle block { const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) diff --git a/packages/jellyfish-testing/src/token.ts b/packages/jellyfish-testing/src/token.ts index 76807f678b..1a17fd84a7 100644 --- a/packages/jellyfish-testing/src/token.ts +++ b/packages/jellyfish-testing/src/token.ts @@ -43,6 +43,11 @@ export class TestingToken { const to = { [address]: [account] } return await this.rpc.account.sendTokensToAddress({}, to) } + + async getTokenId (symbol: string): Promise { + const tokenInfo = await this.rpc.token.getToken(symbol) + return Object.keys(tokenInfo)[0] + } } interface TestingTokenCreate { From 84f544cd033d58cbba74870e996780c9d9747d41 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Fri, 8 Apr 2022 09:42:02 +0530 Subject: [PATCH 27/32] Added/updated tests as per review comments - part 2 --- .../account/withdrawFutureSwap.test.ts | 246 +++++++++--------- 1 file changed, 128 insertions(+), 118 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 5cbce19ae5..2fffae83da 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -231,6 +231,37 @@ describe('withdrawFutureSwap', () => { // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() expect(currentBlock).toBeLessThan(nextSettleBlock) + + // move to next settle block + await testing.generate(nextSettleBlock - currentBlock) + + // verify that no future swap happened + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${(withdrawAmount * 2).toFixed(8)}@TSLA`]) + } + } }) it('Should withdrawFutureSwap futureswap dusd to dtoken', async () => { @@ -248,14 +279,21 @@ describe('withdrawFutureSwap', () => { await testing.rpc.account.futureSwap(fswap) await testing.generate(1) - const withdrawAmount = swapAmount / 2 + const oneSatoshi = 0.00000001 + const oneSatoshiFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${oneSatoshi.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + + const withdrawAmount = swapAmount - oneSatoshi const withdrawFutureSwap: FutureSwap = { address: tslaAddress, amount: `${withdrawAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } - // withdraw half of the future swap + // withdraw a part of the future swap { const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) expect(typeof result).toStrictEqual('string') @@ -263,7 +301,7 @@ describe('withdrawFutureSwap', () => { await testing.generate(1) } - // check the future swap after withdrawing a half + // check the future swap after withdrawing first part { const pendingFutures = await testing.container.call('listpendingfutureswaps') expect(pendingFutures.length).toStrictEqual(1) @@ -294,9 +332,9 @@ describe('withdrawFutureSwap', () => { } } - // withdraw second half of the future swap + // withdraw second part of the future swap { - const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + const result = await testing.rpc.account.withdrawFutureSwap(oneSatoshiFutureSwap) expect(typeof result).toStrictEqual('string') expect(result.length).toStrictEqual(64) await testing.generate(1) @@ -326,58 +364,27 @@ describe('withdrawFutureSwap', () => { { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${(withdrawAmount * 2).toFixed(8)}@DUSD`]) + expect(balance).toStrictEqual([`${(withdrawAmount + oneSatoshi).toFixed(8)}@DUSD`]) } } // verify that all happened before settle block const currentBlock = await testing.rpc.blockchain.getBlockCount() expect(currentBlock).toBeLessThan(nextSettleBlock) - }) - - it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { - const swapAmount = 1 - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@TSLA` }) - await testing.generate(1) - - const fswap: FutureSwap = { - address: tslaAddress, - amount: `${swapAmount.toFixed(8)}@TSLA` - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - const withdrawAmount = swapAmount * 1.5 - const withdrawFutureSwap: FutureSwap = { - address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` - } + // move to next settle block + await testing.generate(nextSettleBlock - currentBlock) - // withdraw from both of the future swaps - { - const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) - expect(typeof result).toStrictEqual('string') - expect(result.length).toStrictEqual(64) - await testing.generate(1) - } - - // check the future swap after withdrawing + // verify that no future swap happened { const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`) - expect(pendingFutures[0].destination).toStrictEqual('DUSD') + expect(pendingFutures.length).toStrictEqual(0) // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) // dfip2203 burn should be empty const burnBefore = await testing.rpc.account.getBurnInfo() @@ -386,68 +393,58 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) + expect(balance).toStrictEqual([]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@TSLA`]) + expect(balance).toStrictEqual([`${(withdrawAmount + oneSatoshi).toFixed(8)}@DUSD`]) } } - - // verify that all happened before settle block - const currentBlock = await testing.rpc.blockchain.getBlockCount() - expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should withdrawFutureSwap from multiple futureswaps dusd to dtoken', async () => { + it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@DUSD` }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@TSLA` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, - amount: `${swapAmount.toFixed(8)}@DUSD`, - destination: 'TSLA' + amount: `${swapAmount.toFixed(8)}@TSLA` } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) await testing.rpc.account.futureSwap(fswap) await testing.generate(1) - const withdrawFutureSwap1: FutureSwap = { - address: tslaAddress, - amount: `${(swapAmount * 0.8).toFixed(8)}@DUSD`, - destination: 'TSLA' - } - const withdrawFutureSwap2: FutureSwap = { + const withdrawAmount = swapAmount * 1.5 + const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${(swapAmount * 1.2).toFixed(8)}@DUSD`, - destination: 'TSLA' + amount: `${withdrawAmount.toFixed(8)}@TSLA` } - // withdraw all within the same block + // withdraw from both of the future swaps { - const result1 = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap1) - expect(typeof result1).toStrictEqual('string') - expect(result1.length).toStrictEqual(64) - const result2 = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap2) - expect(typeof result2).toStrictEqual('string') - expect(result2.length).toStrictEqual(64) + const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) await testing.generate(1) } - // check the future swap after withdrawing all + // check the future swap after withdrawing { const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`) + expect(pendingFutures[0].destination).toStrictEqual('DUSD') // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -458,44 +455,25 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([]) + expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${(swapAmount * 2).toFixed(8)}@DUSD`]) + expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@TSLA`]) } } - // verify that all happened before settle block - const currentBlock = await testing.rpc.blockchain.getBlockCount() - expect(currentBlock).toBeLessThan(nextSettleBlock) - }) - - it('Should withdrawFutureSwap 1 satoshi futureswap dtoken to dusd', async () => { - const swapAmount = 1 - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) - await testing.generate(1) - - const fswap: FutureSwap = { + const oneSatoshi = 0.00000001 + const oneSatoshiFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${swapAmount.toFixed(8)}@TSLA` - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - const withdrawAmount = 0.00000001 - const withdrawFutureSwap: FutureSwap = { - address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` + amount: `${oneSatoshi.toFixed(8)}@TSLA` } // withdraw 1 satoshi { - const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + const result = await testing.rpc.account.withdrawFutureSwap(oneSatoshiFutureSwap) expect(typeof result).toStrictEqual('string') expect(result.length).toStrictEqual(64) await testing.generate(1) @@ -506,12 +484,12 @@ describe('withdrawFutureSwap', () => { const pendingFutures = await testing.container.call('listpendingfutureswaps') expect(pendingFutures.length).toStrictEqual(1) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`) + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`) expect(pendingFutures[0].destination).toStrictEqual('DUSD') // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -522,13 +500,13 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@TSLA`]) + expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@TSLA`]) + expect(balance).toStrictEqual([`${(withdrawAmount + oneSatoshi).toFixed(8)}@TSLA`]) } } @@ -537,11 +515,11 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should withdrawFutureSwap 1 satoshi futureswap dusd to dtoken', async () => { + it('Should withdrawFutureSwap from multiple futureswaps dusd to dtoken', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@DUSD` }) await testing.generate(1) const fswap: FutureSwap = { @@ -551,33 +529,39 @@ describe('withdrawFutureSwap', () => { } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) - const withdrawAmount = 0.00000001 - const withdrawFutureSwap: FutureSwap = { + const withdrawFutureSwap1: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, + amount: `${(swapAmount * 0.8).toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const withdrawFutureSwap2: FutureSwap = { + address: tslaAddress, + amount: `${(swapAmount * 1.2).toFixed(8)}@DUSD`, destination: 'TSLA' } - // withdraw 1 satoshi + // withdraw all within the same block { - const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) - expect(typeof result).toStrictEqual('string') - expect(result.length).toStrictEqual(64) + const result1 = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap1) + expect(typeof result1).toStrictEqual('string') + expect(result1.length).toStrictEqual(64) + const result2 = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap2) + expect(typeof result2).toStrictEqual('string') + expect(result2.length).toStrictEqual(64) await testing.generate(1) } - // check the future swap after withdrawing 1 satoshi + // check the future swap after withdrawing all { const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) - expect(pendingFutures[0].destination).toStrictEqual('TSLA') + expect(pendingFutures.length).toStrictEqual(0) // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -588,13 +572,13 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + expect(balance).toStrictEqual([]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@DUSD`]) + expect(balance).toStrictEqual([`${(swapAmount * 2).toFixed(8)}@DUSD`]) } } @@ -1077,6 +1061,12 @@ describe('withdrawFutureSwap', () => { // move to next settle block await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + // check the future swap at the settle block + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + } + const withdrawAmount = swapAmount / 2 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, @@ -1096,6 +1086,13 @@ describe('withdrawFutureSwap', () => { } await testing.generate(1) + + // check the future swap after the settle block + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + } + // withdraw after settle block { const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -1122,6 +1119,12 @@ describe('withdrawFutureSwap', () => { // move to next settle block await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) + // check the future swap at the settle block + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + } + const withdrawAmount = swapAmount / 2 const withdrawFutureSwap: FutureSwap = { address: tslaAddress, @@ -1142,6 +1145,13 @@ describe('withdrawFutureSwap', () => { } await testing.generate(1) + + // check the future swap after the settle block + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + } + // withdraw after settle block { const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) From 7923f2aa6b0a844658fe6136acd6788faf9825f9 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Fri, 8 Apr 2022 13:02:38 +0530 Subject: [PATCH 28/32] Added a minor update for the test with multiple future swaps --- .../account/withdrawFutureSwap.test.ts | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 2fffae83da..553d53635c 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -406,18 +406,26 @@ describe('withdrawFutureSwap', () => { it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { const swapAmount = 1 + const swapAmount2 = 10 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount * 2}@TSLA` }) + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount2}@DUSD` }) await testing.generate(1) const fswap: FutureSwap = { address: tslaAddress, amount: `${swapAmount.toFixed(8)}@TSLA` } + const fswap2: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount2}@DUSD`, + destination: 'TSLA' + } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) await testing.rpc.account.futureSwap(fswap) + await testing.rpc.account.futureSwap(fswap2) await testing.generate(1) const withdrawAmount = swapAmount * 1.5 @@ -426,7 +434,7 @@ describe('withdrawFutureSwap', () => { amount: `${withdrawAmount.toFixed(8)}@TSLA` } - // withdraw from both of the future swaps + // withdraw from first 2 future swaps and fswap2 should not be affected { const result = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) expect(typeof result).toStrictEqual('string') @@ -434,17 +442,20 @@ describe('withdrawFutureSwap', () => { await testing.generate(1) } - // check the future swap after withdrawing + // check the future swaps after withdrawing { const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures.length).toStrictEqual(2) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`) expect(pendingFutures[0].destination).toStrictEqual('DUSD') + expect(pendingFutures[1].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[1].source).toStrictEqual(`${swapAmount2.toFixed(8)}@DUSD`) + expect(pendingFutures[1].destination).toStrictEqual('TSLA') // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`, `${swapAmount2.toFixed(8)}@DUSD`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -455,7 +466,7 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`]) + expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount).toFixed(8)}@TSLA`, `${swapAmount2.toFixed(8)}@DUSD`]) } { @@ -471,7 +482,7 @@ describe('withdrawFutureSwap', () => { amount: `${oneSatoshi.toFixed(8)}@TSLA` } - // withdraw 1 satoshi + // withdraw 1 satoshi and fswap2 should not be affected { const result = await testing.rpc.account.withdrawFutureSwap(oneSatoshiFutureSwap) expect(typeof result).toStrictEqual('string') @@ -479,17 +490,20 @@ describe('withdrawFutureSwap', () => { await testing.generate(1) } - // check the future swap after withdrawing 1 satoshi + // check the future swaps after withdrawing 1 satoshi { const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures.length).toStrictEqual(2) expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`) expect(pendingFutures[0].destination).toStrictEqual('DUSD') + expect(pendingFutures[1].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[1].source).toStrictEqual(`${swapAmount2.toFixed(8)}@DUSD`) + expect(pendingFutures[1].destination).toStrictEqual('TSLA') // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`, `${swapAmount2.toFixed(8)}@DUSD`]) expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() @@ -500,7 +514,7 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`]) + expect(balance).toStrictEqual([`${(swapAmount * 2 - withdrawAmount - oneSatoshi).toFixed(8)}@TSLA`, `${swapAmount2.toFixed(8)}@DUSD`]) } { From 88b5bd0d4514f56d9087aaead3fb48c97f8ce07c Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Mon, 11 Apr 2022 11:57:15 +0530 Subject: [PATCH 29/32] Updated/Added tests according to review comments --- .../account/withdrawFutureSwap.test.ts | 291 ++++++++++-------- 1 file changed, 162 insertions(+), 129 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 553d53635c..3758e66ba6 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -262,6 +262,50 @@ describe('withdrawFutureSwap', () => { expect(balance).toStrictEqual([`${(withdrawAmount * 2).toFixed(8)}@TSLA`]) } } + + // withdrawFutureSwap with utxo + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) + await testing.generate(1) + + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const utxo = await testing.container.fundAddress(tslaAddress, 50) + + const txid = await testing.rpc.account.withdrawFutureSwap(fswap, [utxo]) + await testing.generate(1) + + const rawtx = await testing.container.call('getrawtransaction', [txid, true]) + expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) + expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${(swapAmount * 2).toFixed(8)}@TSLA`]) + } + } }) it('Should withdrawFutureSwap futureswap dusd to dtoken', async () => { @@ -402,6 +446,53 @@ describe('withdrawFutureSwap', () => { expect(balance).toStrictEqual([`${(withdrawAmount + oneSatoshi).toFixed(8)}@DUSD`]) } } + + // withdrawFutureSwap with utxo + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) + await testing.generate(1) + + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + const utxo = await testing.container.fundAddress(tslaAddress, 50) + + const txid = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) + await testing.generate(1) + + const rawtx = await testing.container.call('getrawtransaction', [txid, true]) + expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) + expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) + + // check the future is in effect + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(1) + expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) + expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) + expect(pendingFutures[0].destination).toStrictEqual('TSLA') + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${(2 * withdrawAmount + oneSatoshi).toFixed(8)}@DUSD`]) + } + } }) it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { @@ -601,119 +692,6 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should withdrawFutureSwap futureswap dtoken to dusd with utxo', async () => { - const swapAmount = 1 - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) - await testing.generate(1) - - const fswap: FutureSwap = { - address: tslaAddress, - amount: `${swapAmount}@TSLA` - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - const utxo = await testing.container.fundAddress(tslaAddress, 50) - - const txid = await testing.rpc.account.withdrawFutureSwap(fswap, [utxo]) - await testing.generate(1) - - const rawtx = await testing.container.call('getrawtransaction', [txid, true]) - expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) - expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() - - // dfip2203 burn should be empty - const burnBefore = await testing.rpc.account.getBurnInfo() - expect(burnBefore.dfip2203).toStrictEqual([]) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([]) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${swapAmount.toFixed(8)}@TSLA`]) - } - } - }) - - it('Should withdrawFutureSwap futureswap dusd to dtoken with utxo', async () => { - const swapAmount = 1 - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) - await testing.generate(1) - - const fswap: FutureSwap = { - address: tslaAddress, - amount: `${swapAmount.toFixed(8)}@DUSD`, - destination: 'TSLA' - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - const utxo = await testing.container.fundAddress(tslaAddress, 50) - - const withdrawAmount = swapAmount / 2 - const withdrawFutureSwap: FutureSwap = { - address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, - destination: 'TSLA' - } - - const txid = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) - await testing.generate(1) - - const rawtx = await testing.container.call('getrawtransaction', [txid, true]) - expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) - expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) - expect(pendingFutures[0].destination).toStrictEqual('TSLA') - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() - - // dfip2203 burn should be empty - const burnBefore = await testing.rpc.account.getBurnInfo() - expect(burnBefore.dfip2203).toStrictEqual([]) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${withdrawAmount.toFixed(8)}@DUSD`]) - } - } - }) - it('Should not withdrawFutureSwap invalid futureswap dtoken to dusd', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) @@ -778,13 +756,36 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: withdrawfutureswap') } + // withdraw with BTC which is not a loan token + { + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${swapAmount.toFixed(8)}@BTC` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get source loan token 1\', code: -32600, method: withdrawfutureswap') + } + // withdraw from arbitrary address { - const withdrawAmount = swapAmount + const withdrawAddress = 'bcrt1qcnfukr6c78wlz2tqpv8vxe0zu339c06pmm3l30' + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${swapAmount.toFixed(8)}@TSLA` + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Incorrect authorization for bcrt1qcnfukr6c78wlz2tqpv8vxe0zu339c06pmm3l30\', code: -5, method: withdrawfutureswap') + } + + // withdraw from arbitrary valid address + { const withdrawAddress = await testing.generateAddress() const withdrawFutureSwap: FutureSwap = { address: withdrawAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` + amount: `${swapAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -793,12 +794,11 @@ describe('withdrawFutureSwap', () => { // withdraw from arbitrary utxo { - const withdrawAmount = swapAmount const utxoAddress = await testing.generateAddress() const utxo = await testing.container.fundAddress(utxoAddress, 50) const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` + amount: `${swapAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) await expect(result).rejects.toThrow(RpcApiError) @@ -849,10 +849,9 @@ describe('withdrawFutureSwap', () => { const idTSLA = await testing.token.getTokenId('TSLA') await testing.rpc.masternode.setGov({ [attributeKey]: { [`v0/token/${idTSLA}/dfip2203`]: 'false' } }) - const withdrawAmount = swapAmount const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` + amount: `${swapAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -865,10 +864,9 @@ describe('withdrawFutureSwap', () => { { await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) - const withdrawAmount = swapAmount const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` + amount: `${swapAmount.toFixed(8)}@TSLA` } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) await expect(result).rejects.toThrow(RpcApiError) @@ -922,6 +920,19 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get destination loan token 0. Set valid destination.\', code: -32600, method: withdrawfutureswap') } + // withdraw fail - with invalid destination + { + const withdrawAmount = 0.5 + const withdrawFutureSwap: FutureSwap = { + address: tslaAddress, + amount: `${withdrawAmount.toFixed(8)}@DUSD`, + destination: 'INVALID' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Destination token not found\', code: -5, method: withdrawfutureswap') + } + // Withdraw fail - try to withdraw from unavailable futureswap { const withdrawAmount = 0.5 @@ -947,13 +958,38 @@ describe('withdrawFutureSwap', () => { await expect(result).rejects.toThrow('RpcApiError: \': Invalid Defi token: INVALID\', code: 0, method: withdrawfutureswap') } + // withdraw with BTC which is not a loan token + { + const withdrawAddress = await testing.generateAddress() + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${swapAmount.toFixed(8)}@DUSD`, + destination: 'BTC' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\nCould not get destination loan token 1. Set valid destination.\', code: -32600, method: withdrawfutureswap') + } + // withdraw from arbitrary address { - const withdrawAmount = swapAmount + const withdrawAddress = 'bcrt1qcnfukr6c78wlz2tqpv8vxe0zu339c06pmm3l30' + const withdrawFutureSwap: FutureSwap = { + address: withdrawAddress, + amount: `${swapAmount.toFixed(8)}@DUSD`, + destination: 'TSLA' + } + const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + await expect(result).rejects.toThrow(RpcApiError) + await expect(result).rejects.toThrow('RpcApiError: \'Incorrect authorization for bcrt1qcnfukr6c78wlz2tqpv8vxe0zu339c06pmm3l30\', code: -5, method: withdrawfutureswap') + } + + // withdraw from arbitrary valid address + { const withdrawAddress = await testing.generateAddress() const withdrawFutureSwap: FutureSwap = { address: withdrawAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -963,12 +999,11 @@ describe('withdrawFutureSwap', () => { // withdraw from arbitrary utxo { - const withdrawAmount = swapAmount const utxoAddress = await testing.generateAddress() const utxo = await testing.container.fundAddress(utxoAddress, 50) const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) @@ -1023,10 +1058,9 @@ describe('withdrawFutureSwap', () => { const idTSLA = await testing.token.getTokenId('TSLA') await testing.rpc.masternode.setGov({ [attributeKey]: { [`v0/token/${idTSLA}/dfip2203`]: 'false' } }) - const withdrawAmount = swapAmount const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) @@ -1040,10 +1074,9 @@ describe('withdrawFutureSwap', () => { { await testing.rpc.masternode.setGov({ [attributeKey]: { 'v0/params/dfip2203/active': 'false' } }) - const withdrawAmount = swapAmount const withdrawFutureSwap: FutureSwap = { address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, + amount: `${swapAmount.toFixed(8)}@DUSD`, destination: 'TSLA' } const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) From 40a2c817802a7f5b4f525af6f0dd403366562e6d Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Mon, 11 Apr 2022 13:28:40 +0530 Subject: [PATCH 30/32] Updated/Added tests according to review comments 2 --- .../account/withdrawFutureSwap.test.ts | 72 +++++-------------- 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 3758e66ba6..38c7d4f51b 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -262,50 +262,6 @@ describe('withdrawFutureSwap', () => { expect(balance).toStrictEqual([`${(withdrawAmount * 2).toFixed(8)}@TSLA`]) } } - - // withdrawFutureSwap with utxo - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) - await testing.generate(1) - - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - const utxo = await testing.container.fundAddress(tslaAddress, 50) - - const txid = await testing.rpc.account.withdrawFutureSwap(fswap, [utxo]) - await testing.generate(1) - - const rawtx = await testing.container.call('getrawtransaction', [txid, true]) - expect(rawtx.vin[0].txid).toStrictEqual(utxo.txid) - expect(rawtx.vin[0].vout).toStrictEqual(utxo.vout) - - // check the future is in effect - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - - // check live/economy/dfip2203_* - const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) - - // dfip2203 burn should be empty - const burnBefore = await testing.rpc.account.getBurnInfo() - expect(burnBefore.dfip2203).toStrictEqual([]) - - { - // check contractAddress - const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([]) - } - - { - // check tslaAddress - const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${(swapAmount * 2).toFixed(8)}@TSLA`]) - } - } }) it('Should withdrawFutureSwap futureswap dusd to dtoken', async () => { @@ -446,17 +402,24 @@ describe('withdrawFutureSwap', () => { expect(balance).toStrictEqual([`${(withdrawAmount + oneSatoshi).toFixed(8)}@DUSD`]) } } + }) - // withdrawFutureSwap with utxo - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@DUSD` }) + it('Should withdrawFutureSwap futureswap dtoken to dusd with utxo', async () => { + const swapAmount = 1 + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) await testing.generate(1) + const fswap: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount}@TSLA` + } await testing.rpc.account.futureSwap(fswap) await testing.generate(1) const utxo = await testing.container.fundAddress(tslaAddress, 50) - const txid = await testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap, [utxo]) + const txid = await testing.rpc.account.withdrawFutureSwap(fswap, [utxo]) await testing.generate(1) const rawtx = await testing.container.call('getrawtransaction', [txid, true]) @@ -466,16 +429,13 @@ describe('withdrawFutureSwap', () => { // check the future is in effect { const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(1) - expect(pendingFutures[0].owner).toStrictEqual(tslaAddress) - expect(pendingFutures[0].source).toStrictEqual(`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`) - expect(pendingFutures[0].destination).toStrictEqual('TSLA') + expect(pendingFutures.length).toStrictEqual(0) // check live/economy/dfip2203_* const attributes = await testing.rpc.masternode.getGov(attributeKey) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) - expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toBeUndefined() + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toBeUndefined() // dfip2203 burn should be empty const burnBefore = await testing.rpc.account.getBurnInfo() @@ -484,13 +444,13 @@ describe('withdrawFutureSwap', () => { { // check contractAddress const balance = await testing.rpc.account.getAccount(contractAddress) - expect(balance).toStrictEqual([`${(swapAmount - withdrawAmount).toFixed(8)}@DUSD`]) + expect(balance).toStrictEqual([]) } { // check tslaAddress const balance = await testing.rpc.account.getAccount(tslaAddress) - expect(balance).toStrictEqual([`${(2 * withdrawAmount + oneSatoshi).toFixed(8)}@DUSD`]) + expect(balance).toStrictEqual([`${swapAmount.toFixed(8)}@TSLA`]) } } }) From fea542cbef5c8b932d38e55d3456f9b5ba2f535a Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Mon, 11 Apr 2022 14:34:37 +0530 Subject: [PATCH 31/32] Updated/Added tests according to review comments 3 --- .../account/withdrawFutureSwap.test.ts | 146 +++++++----------- 1 file changed, 58 insertions(+), 88 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 38c7d4f51b..35b93afca9 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -404,7 +404,7 @@ describe('withdrawFutureSwap', () => { } }) - it('Should withdrawFutureSwap futureswap dtoken to dusd with utxo', async () => { + it('Should withdrawFutureSwap futureswap with utxo', async () => { const swapAmount = 1 const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) @@ -455,6 +455,60 @@ describe('withdrawFutureSwap', () => { } }) + it('Should withdrawFutureSwap futureswap - at the settle block', async () => { + const swapAmount = 1 + const nextSettleBlock = await testing.container.call('getfutureswapblock', []) + const tslaAddress = await testing.generateAddress() + await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) + await testing.generate(1) + + const fswap: FutureSwap = { + address: tslaAddress, + amount: `${swapAmount.toFixed(8)}@TSLA` + } + await testing.rpc.account.futureSwap(fswap) + await testing.generate(1) + + // move to next settle block + await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount() - 1) + + // withdraw at the settle block + { + const result = await testing.rpc.account.withdrawFutureSwap(fswap) + expect(typeof result).toStrictEqual('string') + expect(result.length).toStrictEqual(64) + await testing.generate(1) + } + + // check the future swap after settle block + { + const pendingFutures = await testing.container.call('listpendingfutureswaps') + expect(pendingFutures.length).toStrictEqual(0) + + // check live/economy/dfip2203_* + const attributes = await testing.rpc.masternode.getGov(attributeKey) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_current']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_burned']).toStrictEqual([]) + expect(attributes.ATTRIBUTES['v0/live/economy/dfip2203_minted']).toStrictEqual([]) + + // dfip2203 burn should be empty + const burnBefore = await testing.rpc.account.getBurnInfo() + expect(burnBefore.dfip2203).toStrictEqual([]) + + { + // check contractAddress + const balance = await testing.rpc.account.getAccount(contractAddress) + expect(balance).toStrictEqual([]) + } + + { + // check tslaAddress + const balance = await testing.rpc.account.getAccount(tslaAddress) + expect(balance).toStrictEqual([`${swapAmount.toFixed(8)}@TSLA`]) + } + } + }) + it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { const swapAmount = 1 const swapAmount2 = 10 @@ -1051,64 +1105,7 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should not withdrawFutureSwap futureswap dtoken to dusd - at/after the settle block', async () => { - const swapAmount = 1 - const nextSettleBlock = await testing.container.call('getfutureswapblock', []) - const tslaAddress = await testing.generateAddress() - await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) - await testing.generate(1) - - const fswap: FutureSwap = { - address: tslaAddress, - amount: `${swapAmount.toFixed(8)}@TSLA` - } - await testing.rpc.account.futureSwap(fswap) - await testing.generate(1) - - // move to next settle block - await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) - - // check the future swap at the settle block - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - } - - const withdrawAmount = swapAmount / 2 - const withdrawFutureSwap: FutureSwap = { - address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@TSLA` - } - - // withdraw at the settle block - { - const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) - await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') - } - { - const result = testing.rpc.account.withdrawFutureSwap(fswap) - await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') - } - - await testing.generate(1) - - // check the future swap after the settle block - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - } - - // withdraw after settle block - { - const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) - await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') - } - }) - - it('Should not withdrawFutureSwap futureswap dusd to dtoken - at/after the settle block', async () => { + it('Should not withdrawFutureSwap futureswap - after the settle block', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -1126,33 +1123,6 @@ describe('withdrawFutureSwap', () => { // move to next settle block await testing.generate(nextSettleBlock - await testing.rpc.blockchain.getBlockCount()) - // check the future swap at the settle block - { - const pendingFutures = await testing.container.call('listpendingfutureswaps') - expect(pendingFutures.length).toStrictEqual(0) - } - - const withdrawAmount = swapAmount / 2 - const withdrawFutureSwap: FutureSwap = { - address: tslaAddress, - amount: `${withdrawAmount.toFixed(8)}@DUSD`, - destination: 'TSLA' - } - - // withdraw at the settle block - { - const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) - await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') - } - { - const result = testing.rpc.account.withdrawFutureSwap(fswap) - await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') - } - - await testing.generate(1) - // check the future swap after the settle block { const pendingFutures = await testing.container.call('listpendingfutureswaps') @@ -1161,9 +1131,9 @@ describe('withdrawFutureSwap', () => { // withdraw after settle block { - const result = testing.rpc.account.withdrawFutureSwap(withdrawFutureSwap) + const result = testing.rpc.account.withdrawFutureSwap(fswap) await expect(result).rejects.toThrow(RpcApiError) - await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 0.50000000\', code: -32600, method: withdrawfutureswap') + await expect(result).rejects.toThrow('RpcApiError: \'Test DFIP2203Tx execution failed:\namount 0.00000000 is less than 1.00000000\', code: -32600, method: withdrawfutureswap') } }) }) From e345d18a2f8c1ba49c1bce2f65b041e9e610b901 Mon Sep 17 00:00:00 2001 From: Chanaka Sameera Date: Mon, 11 Apr 2022 15:35:57 +0530 Subject: [PATCH 32/32] Updated test case names --- .../account/withdrawFutureSwap.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts index 35b93afca9..a958f3cd97 100644 --- a/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/account/withdrawFutureSwap.test.ts @@ -133,7 +133,7 @@ describe('withdrawFutureSwap', () => { await testing.container.stop() }) - it('Should withdrawFutureSwap futureswap dtoken to dusd', async () => { + it('should withdrawFutureSwap futureswap dtoken to dusd', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -264,7 +264,7 @@ describe('withdrawFutureSwap', () => { } }) - it('Should withdrawFutureSwap futureswap dusd to dtoken', async () => { + it('should withdrawFutureSwap futureswap dusd to dtoken', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -404,7 +404,7 @@ describe('withdrawFutureSwap', () => { } }) - it('Should withdrawFutureSwap futureswap with utxo', async () => { + it('should withdrawFutureSwap futureswap with utxo', async () => { const swapAmount = 1 const tslaAddress = await testing.generateAddress() await testing.rpc.account.accountToAccount(collateralAddress, { [tslaAddress]: `${swapAmount}@TSLA` }) @@ -455,7 +455,7 @@ describe('withdrawFutureSwap', () => { } }) - it('Should withdrawFutureSwap futureswap - at the settle block', async () => { + it('should withdrawFutureSwap futureswap - at the settle block', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -509,7 +509,7 @@ describe('withdrawFutureSwap', () => { } }) - it('Should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { + it('should withdrawFutureSwap from multiple futureswaps dtoken to dusd', async () => { const swapAmount = 1 const swapAmount2 = 10 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) @@ -634,7 +634,7 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should withdrawFutureSwap from multiple futureswaps dusd to dtoken', async () => { + it('should withdrawFutureSwap from multiple futureswaps dusd to dtoken', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -706,7 +706,7 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should not withdrawFutureSwap invalid futureswap dtoken to dusd', async () => { + it('should not withdrawFutureSwap invalid futureswap dtoken to dusd', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -894,7 +894,7 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should not withdrawFutureSwap invalid futureswap dusd to dtoken', async () => { + it('should not withdrawFutureSwap invalid futureswap dusd to dtoken', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress() @@ -1105,7 +1105,7 @@ describe('withdrawFutureSwap', () => { expect(currentBlock).toBeLessThan(nextSettleBlock) }) - it('Should not withdrawFutureSwap futureswap - after the settle block', async () => { + it('should not withdrawFutureSwap futureswap - after the settle block', async () => { const swapAmount = 1 const nextSettleBlock = await testing.container.call('getfutureswapblock', []) const tslaAddress = await testing.generateAddress()