diff --git a/ride/factory_v2.ride b/ride/factory_v2.ride index 8a642c97d..73e6219c0 100644 --- a/ride/factory_v2.ride +++ b/ride/factory_v2.ride @@ -176,6 +176,14 @@ func keyMinBalance(poolAddress: String, assetId: String) func keyMinBalanceDefault(assetId: String) = makeString(["%s%s", "minBalanceDefault", assetId], SEP) +#------------------------ +# SWAP FUNCTIONS +#------------------------ + +func keySwapProtocolFee() = ["%s", "protocolFee"].makeString(SEP) +func keySwapPoolFee() = ["%s", "poolFee"].makeString(SEP) +func keyFeeCollectorAddress() = ["%s", "feeCollectorAddress"].makeString(SEP) + #------------------------ # GLOBAL FUNCTIONS #------------------------ diff --git a/ride/swap.ride b/ride/swap.ride index 51872628f..472e72bae 100644 --- a/ride/swap.ride +++ b/ride/swap.ride @@ -26,7 +26,11 @@ let factoryContract = addressFromStringValue(getStringOrFail(fc())) func protocolFee() = ["%s", "protocolFee"].makeString(SEP) func poolFee() = ["%s", "poolFee"].makeString(SEP) -func getStringOrFailFromAddress(address: Address, key: String) = address.getString(key).valueOrErrorMessage(makeString(["mandatory ", address.toString(), ".", key, " is not defined"], "")) +func getStringOrFailFromAddress(address: Address, key: String) = { + address.getString(key).valueOrErrorMessage( + makeString(["mandatory ", address.toString(), ".", key, " is not defined"], "") + ) +} let keyFeeCollectorAddress = "%s__feeCollectorAddress" let feeCollectorAddress = factoryContract.getStringOrFailFromAddress(keyFeeCollectorAddress).addressFromStringValue() @@ -78,8 +82,8 @@ func getAccBalance(assetId: String) = { # %d%d__poolFee__protocolFee func getSwapFees(poolAddressStr: String) = { - let poolFeeDefault = this.getInteger(poolFee()).value() - let protocolFeeDefault = this.getInteger(protocolFee()).value() + let poolFeeDefault = factoryContract.getIntegerValue(poolFee()) + let protocolFeeDefault = factoryContract.getIntegerValue(protocolFee()) match factoryContract.invoke("getSwapFeeREADONLY", [poolAddressStr], []) { case fees: (Int, Int) => (fees._1, fees._2) diff --git a/test/components/swap/_hooks.mjs b/test/components/swap/_hooks.mjs new file mode 100644 index 000000000..2f14c00f2 --- /dev/null +++ b/test/components/swap/_hooks.mjs @@ -0,0 +1,410 @@ +import { address, publicKey, randomSeed } from '@waves/ts-lib-crypto'; +import { + data, + invokeScript, + issue, + massTransfer, + nodeInteraction, +} from '@waves/waves-transactions'; +import { create } from '@waves/node-api-js'; +import { format } from 'path'; +import { setScriptFromFile } from '../../utils/utils.mjs'; + +const { waitForTx } = nodeInteraction; +const apiBase = process.env.API_NODE_URL; +const seed = 'waves private node seed with waves tokens'; +const chainId = 'R'; +const api = create(apiBase); +const seedWordsCount = 5; +const ridePath = '../ride'; +const mockRidePath = 'components/lp_stable/mock'; + +const swapPath = format({ dir: ridePath, base: 'swap.ride' }); +const lpStablePath = format({ dir: ridePath, base: 'lp_stable.ride' }); +const lpPath = format({ dir: ridePath, base: 'lp.ride' }); +const factoryV2Path = format({ dir: ridePath, base: 'factory_v2.ride' }); +const stakingPath = format({ dir: mockRidePath, base: 'staking.mock.ride' }); +const slippagePath = format({ dir: mockRidePath, base: 'slippage.mock.ride' }); +const assetsStorePath = format({ dir: mockRidePath, base: 'assets_store.mock.ride' }); +const gwxRewardPath = format({ dir: mockRidePath, base: 'gwx_reward.mock.ride' }); +const restPath = format({ dir: ridePath, base: 'rest.ride' }); + +export const mochaHooks = { + async beforeAll() { + const names = [ + 'swap', + 'lp', + 'lpStable', + 'factoryV2', + 'staking', + 'slippage', + 'gwxReward', + 'manager', + 'store', + 'feeCollector', + 'rest', + 'user1', + ]; + this.accounts = Object.fromEntries(names.map((item) => [item, randomSeed(seedWordsCount)])); + const seeds = Object.values(this.accounts); + const amount = 1e10; + const massTransferTx = massTransfer({ + transfers: seeds.map((item) => ({ recipient: address(item, chainId), amount })), + chainId, + }, seed); + await api.transactions.broadcast(massTransferTx, {}); + await waitForTx(massTransferTx.id, { apiBase }); + + await setScriptFromFile(swapPath, this.accounts.swap); + await setScriptFromFile(lpPath, this.accounts.lp); + await setScriptFromFile(lpStablePath, this.accounts.lpStable); + await setScriptFromFile(factoryV2Path, this.accounts.factoryV2); + await setScriptFromFile(stakingPath, this.accounts.staking); + await setScriptFromFile(slippagePath, this.accounts.slippage); + await setScriptFromFile(assetsStorePath, this.accounts.store); + await setScriptFromFile(gwxRewardPath, this.accounts.gwxReward); + await setScriptFromFile(restPath, this.accounts.rest); + + const usdnIssueTx = issue({ + name: 'USDN', + description: '', + quantity: 10e17, + decimals: 6, + chainId, + }, seed); + await api.transactions.broadcast(usdnIssueTx, {}); + await waitForTx(usdnIssueTx.id, { apiBase }); + this.usdnAssetId = usdnIssueTx.id; + + const usdnAmount = 1e16; + const massTransferTxUSDN = massTransfer({ + transfers: names.slice(-1).map((name) => ({ + recipient: address(this.accounts[name], chainId), amount: usdnAmount, + })), + assetId: this.usdnAssetId, + chainId, + }, seed); + await api.transactions.broadcast(massTransferTxUSDN, {}); + await waitForTx(massTransferTxUSDN.id, { apiBase }); + + const usdtIssueTx = issue({ + name: 'USDT', + description: '', + quantity: 10e16, + decimals: 6, + chainId, + }, seed); + await api.transactions.broadcast(usdtIssueTx, {}); + await waitForTx(usdtIssueTx.id, { apiBase }); + this.usdtAssetId = usdtIssueTx.id; + + const usdtAmount = 1e16; + const massTransferTxUSDT = massTransfer({ + transfers: names.slice(-1).map((name) => ({ + recipient: address(this.accounts[name], chainId), amount: usdtAmount, + })), + assetId: this.usdtAssetId, + chainId, + }, seed); + await api.transactions.broadcast(massTransferTxUSDT, {}); + await waitForTx(massTransferTxUSDT.id, { apiBase }); + + const shibIssueTx = issue({ + name: 'SHIB', + description: '', + quantity: 100000e2, + decimals: 2, + chainId, + }, seed); + await api.transactions.broadcast(shibIssueTx, {}); + await waitForTx(shibIssueTx.id, { apiBase }); + this.shibAssetId = shibIssueTx.id; + + const shibAmount = 100e2; + const massTransferTxSHIB = massTransfer({ + transfers: names.slice(-1).map((name) => ({ + recipient: address(this.accounts[name], chainId), amount: shibAmount, + })), + assetId: this.shibAssetId, + chainId, + }, seed); + await api.transactions.broadcast(massTransferTxSHIB, {}); + await waitForTx(massTransferTxSHIB.id, { apiBase }); + + const constructorFactoryV2InvokeTx = invokeScript({ + dApp: address(this.accounts.factoryV2, chainId), + additionalFee: 4e5, + call: { + function: 'constructor', + args: [ + { type: 'string', value: address(this.accounts.staking, chainId) }, + { type: 'string', value: '' }, + { type: 'string', value: '' }, + { type: 'string', value: '' }, + { type: 'string', value: '' }, + { type: 'string', value: address(this.accounts.rest, chainId) }, + { type: 'string', value: address(this.accounts.slippage, chainId) }, + { type: 'integer', value: 8 }, + ], + }, + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(constructorFactoryV2InvokeTx, {}); + await waitForTx(constructorFactoryV2InvokeTx.id, { apiBase }); + + const constructorV2FactoryV2InvokeTx = invokeScript({ + dApp: address(this.accounts.factoryV2, chainId), + additionalFee: 4e5, + call: { + function: 'constructorV2', + args: [ + { type: 'string', value: publicKey(this.accounts.manager) }, + ], + }, + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(constructorV2FactoryV2InvokeTx, {}); + await waitForTx(constructorV2FactoryV2InvokeTx.id, { apiBase }); + + const constructorV3FactoryV2InvokeTx = invokeScript({ + dApp: address(this.accounts.factoryV2, chainId), + additionalFee: 4e5, + call: { + function: 'constructorV3', + args: [ + { type: 'string', value: '' }, + { type: 'string', value: '' }, + { type: 'string', value: address(this.accounts.gwxReward, chainId) }, + { type: 'string', value: '' }, + ], + }, + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(constructorV3FactoryV2InvokeTx, {}); + await waitForTx(constructorV3FactoryV2InvokeTx.id, { apiBase }); + + const constructorV4FactoryV2InvokeTx = invokeScript({ + dApp: address(this.accounts.factoryV2, chainId), + additionalFee: 4e5, + call: { + function: 'constructorV4', + args: [ + { type: 'string', value: '' }, + { type: 'list', value: [{ type: 'string', value: '' }] }, + ], + }, + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(constructorV4FactoryV2InvokeTx, {}); + await waitForTx(constructorV4FactoryV2InvokeTx.id, { apiBase }); + + const constructorV5FactoryV2InvokeTx = invokeScript({ + dApp: address(this.accounts.factoryV2, chainId), + additionalFee: 4e5, + call: { + function: 'constructorV5', + args: [ + { type: 'string', value: address(this.accounts.store, chainId) }, + ], + }, + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(constructorV5FactoryV2InvokeTx, {}); + await waitForTx(constructorV5FactoryV2InvokeTx.id, { apiBase }); + + const constructorRestInvokeTx = invokeScript({ + dApp: address(this.accounts.rest, chainId), + additionalFee: 4e5, + call: { + function: 'constructor', + args: [ + { type: 'string', value: address(this.accounts.factoryV2, chainId) }, + ], + }, + chainId, + }, this.accounts.rest); + await api.transactions.broadcast(constructorRestInvokeTx, {}); + await waitForTx(constructorRestInvokeTx.id, { apiBase }); + + const setFeeCollectorFactoryV2Tx = data({ + additionalFee: 4e5, + data: [{ + key: '%s__feeCollectorAddress', + type: 'string', + value: address(this.accounts.feeCollector, chainId), + }], + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(setFeeCollectorFactoryV2Tx, {}); + await waitForTx(setFeeCollectorFactoryV2Tx.id, { apiBase }); + + const poolFee = 10e4; + const protocolFee = 10e4; + + const setDefaultInOutFeeTx = data({ + additionalFee: 4e5, + data: [{ + key: '%s__inFeeDefault', + type: 'integer', + value: '100000', + }, { + key: '$s__outFeeDefault', + type: 'integer', + value: '100000', + + }, { + key: '%s__swapContract', + type: 'string', + value: address(this.accounts.swap, chainId), + }, + { + key: '%s__poolFee', + type: 'integer', + value: poolFee, + }, + { + key: '%s__protocolFee', + type: 'integer', + value: protocolFee, + }, + ], + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(setDefaultInOutFeeTx, {}); + await waitForTx(setDefaultInOutFeeTx.id, { apiBase }); + + const setManagerFactoryV2Tx = data({ + additionalFee: 4e5, + data: [{ + key: '%s__managerPublicKey', + type: 'string', + value: publicKey(this.accounts.manager), + }], + chainId, + }, this.accounts.factoryV2); + await api.transactions.broadcast(setManagerFactoryV2Tx, {}); + await waitForTx(setManagerFactoryV2Tx.id, { apiBase }); + + const setFactoryContractToLpStableTx = data({ + additionalFee: 4e5, + data: [ + { + key: '%s__factoryContract', + type: 'string', + value: address(this.accounts.factoryV2, chainId), + }, + ], + chainId, + }, this.accounts.lpStable); + await api.transactions.broadcast(setFactoryContractToLpStableTx, {}); + await waitForTx(setFactoryContractToLpStableTx.id, { apiBase }); + + const setFactoryContractToLpTx = data({ + additionalFee: 4e5, + data: [ + { + key: '%s__factoryContract', + type: 'string', + value: address(this.accounts.factoryV2, chainId), + }, + ], + chainId, + }, this.accounts.lp); + await api.transactions.broadcast(setFactoryContractToLpTx, {}); + await waitForTx(setFactoryContractToLpTx.id, { apiBase }); + + const setSwapKeysTx = data({ + additionalFee: 4e5, + data: [ + { + key: '%s__factoryContract', + type: 'string', + value: address(this.accounts.factoryV2, chainId), + }, + ], + chainId, + }, this.accounts.swap); + await api.transactions.broadcast(setSwapKeysTx, {}); + await waitForTx(setSwapKeysTx.id, { apiBase }); + + const constructorLpStableInvokeTx = invokeScript({ + dApp: address(this.accounts.lpStable, chainId), + additionalFee: 4e5, + call: { + function: 'constructor', + args: [ + { type: 'string', value: address(this.accounts.factoryV2, chainId) }, + ], + }, + chainId, + }, this.accounts.lpStable); + await api.transactions.broadcast(constructorLpStableInvokeTx, {}); + await waitForTx(constructorLpStableInvokeTx.id, { apiBase }); + + const activateNewPoolTx = invokeScript({ + dApp: address(this.accounts.factoryV2, chainId), + fee: 100500000, + call: { + function: 'activateNewPool', + args: [ + { type: 'string', value: address(this.accounts.lpStable, chainId) }, + { type: 'string', value: this.usdtAssetId }, + { type: 'string', value: this.usdnAssetId }, + { type: 'string', value: 'USDTUSDNLP' }, + { type: 'string', value: 'WX USDT/USDN pool liquidity provider token' }, + { type: 'integer', value: 0 }, + { type: 'string', value: '' }, + { type: 'string', value: '' }, + ], + }, + chainId, + }, this.accounts.manager); + await api.transactions.broadcast(activateNewPoolTx, {}); + const { stateChanges } = await waitForTx(activateNewPoolTx.id, { apiBase }); + this.lpStableAssetId = stateChanges.issues[0].assetId; + + const setDelayTx = data({ + additionalFee: 4e5, + data: [{ + key: '%s__delay', + type: 'integer', + value: 2, + }], + chainId, + }, this.accounts.lpStable); + await api.transactions.broadcast(setDelayTx, {}); + await waitForTx(setDelayTx.id, { apiBase }); + + const setAmpTx = data({ + additionalFee: 4e5, + data: [{ + key: '%s__amp', + type: 'string', + value: '250', + }], + chainId, + }, this.accounts.lpStable); + await api.transactions.broadcast(setAmpTx, {}); + await waitForTx(setAmpTx.id, { apiBase }); + + const setManagerLpStableTx = data({ + additionalFee: 4e5, + data: [{ + key: '%s__managerPublicKey', + type: 'string', + value: publicKey(this.accounts.manager), + }], + chainId, + }, this.accounts.lpStable); + await api.transactions.broadcast(setManagerLpStableTx, {}); + await waitForTx(setManagerLpStableTx.id, { apiBase }); + + console.log('lpStableAddress', address(this.accounts.lpStable, chainId)); + console.log('lpAddress', address(this.accounts.lp, chainId)); + console.log('swap', address(this.accounts.swap, chainId)); + console.log('managerAddress', address(this.accounts.manager, chainId)); + console.log('factoryV2Address', address(this.accounts.factoryV2, chainId)); + console.log('assetsStoreAddress', address(this.accounts.store, chainId)); + console.log('user1', address(this.accounts.user1, chainId)); + }, +}; diff --git a/test/components/swap/contract/lp_stable.mjs b/test/components/swap/contract/lp_stable.mjs new file mode 100644 index 000000000..cdc791ddf --- /dev/null +++ b/test/components/swap/contract/lp_stable.mjs @@ -0,0 +1,132 @@ +import { invokeScript, data } from '@waves/waves-transactions'; +import { broadcastAndWait, chainId } from '../../../utils/api.mjs'; + +export const lpStable = { + put: async ({ + dApp, caller, + amountAssetId, amountAssetAmount, + priceAssetId, priceAssetAmount, + slippageTolerance = 0, + autoStake = false, + }) => { + const invokeTx = invokeScript( + { + dApp, + call: { + function: 'put', + args: [ + { type: 'integer', value: slippageTolerance }, + { type: 'boolean', value: autoStake }, + ], + }, + payment: [ + { assetId: amountAssetId, amount: amountAssetAmount }, + { assetId: priceAssetId, amount: priceAssetAmount }, + ], + additionalFee: 4e5, + chainId, + }, + caller, + ); + return broadcastAndWait(invokeTx); + }, + + putOneTknV2: async ({ + dApp, caller, + assetId, amount, + minOutAmount = 0, + autoStake = false, + }) => { + const invokeTx = invokeScript( + { + dApp, + call: { + function: 'putOneTknV2', + args: [ + { type: 'integer', value: minOutAmount }, + { type: 'boolean', value: autoStake }, + ], + }, + payment: [ + { assetId, amount }, + ], + additionalFee: 4e5, + chainId, + }, + caller, + ); + return broadcastAndWait(invokeTx); + }, + + getOneTknV2: async ({ + dApp, caller, + outAssetId, + lpAssetId, lpAssetAmount, + minOutAmount = 0, + }) => { + const invokeTx = invokeScript( + { + dApp, + call: { + function: 'getOneTknV2', + args: [ + { type: 'string', value: outAssetId }, + { type: 'integer', value: minOutAmount }, + ], + }, + payment: [ + { assetId: lpAssetId, amount: lpAssetAmount }, + ], + additionalFee: 4e5, + chainId, + }, + caller, + ); + return broadcastAndWait(invokeTx); + }, + + unstakeAndGetOneTknV2: async ({ + dApp, caller, + unstakeAmount, + outAssetId, + minOutAmount = 0, + }) => { + const invokeTx = invokeScript( + { + dApp, + call: { + function: 'unstakeAndGetOneTknV2', + args: [ + { type: 'integer', value: unstakeAmount }, + { type: 'string', value: outAssetId }, + { type: 'integer', value: minOutAmount }, + ], + }, + payment: [], + additionalFee: 4e5, + chainId, + }, + caller, + ); + return broadcastAndWait(invokeTx); + }, + + setFee: async ({ + senderPublicKey, caller, + value, + }) => { + const key = '%s__fee'; + const dataTx = data( + { + data: [ + { key, type: 'integer', value }, + ], + additionalFee: 4e5, + senderPublicKey, + chainId, + }, + caller, + ); + return broadcastAndWait(dataTx); + }, +}; diff --git a/test/components/swap/mock/assets_store.mock.ride b/test/components/swap/mock/assets_store.mock.ride new file mode 100644 index 000000000..42014d193 --- /dev/null +++ b/test/components/swap/mock/assets_store.mock.ride @@ -0,0 +1,50 @@ +{-# STDLIB_VERSION 5 #-} +{-# CONTENT_TYPE DAPP #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +let SEP = "__" + +let statusVerified = 2 +let statusUnverified = 0 + +func keyStatus(assetId: String) = "status_<"+assetId+">" + +func isVerified(assetId: String) = { + assetId.keyStatus().getInteger().valueOrElse(statusUnverified) == statusVerified +} + +@Callable(i) +func createOrUpdate(assetId: String, logo: String, verified: Boolean) = { + (nil, unit) +} + +@Callable(i) +func addLabel(assetId: String, label: String) = { + (nil, unit) +} + +@Callable(i) +func addAssetsLink(amountAsset: String, priceAsset: String, lpAsset: String) = { + (nil, unit) +} + +@Callable(i) +func increaseAssetPoolsNumber(assetId: String) = { + (nil, unit) +} + +@Callable(i) +func setVerified(assetId: String, verified: Boolean) = { + (nil, unit) +} + +@Callable(i) +func setLogo(assetId: String, logo: String) = { + (nil, unit) +} + +@Callable(i) +func isVerifiedREADONLY(assetId: String) = { + # (nil, assetId.getBoolean().valueOrElse(false)) + (nil, assetId.isVerified()) +} diff --git a/test/components/swap/mock/gwx_reward.mock.ride b/test/components/swap/mock/gwx_reward.mock.ride new file mode 100644 index 000000000..edf4dae45 --- /dev/null +++ b/test/components/swap/mock/gwx_reward.mock.ride @@ -0,0 +1,14 @@ +{-# STDLIB_VERSION 5 #-} +{-# CONTENT_TYPE DAPP #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +@Callable(i) +func calcD( + x1BigIntStr: String, + x2BigIntStr: String, + ampBigIntStr: String, + aPrecisionBigIntStr: String, + targetPrecisionBigIntStr: String +) = { + ([], 1000.toString()) +} diff --git a/test/components/swap/mock/slippage.mock.ride b/test/components/swap/mock/slippage.mock.ride new file mode 100644 index 000000000..cdeb0d811 --- /dev/null +++ b/test/components/swap/mock/slippage.mock.ride @@ -0,0 +1,8 @@ +{-# STDLIB_VERSION 5 #-} +{-# CONTENT_TYPE DAPP #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +@Callable(i) +func put() = { + (nil, unit) +} diff --git a/test/components/swap/mock/staking.mock.ride b/test/components/swap/mock/staking.mock.ride new file mode 100644 index 000000000..f54045b77 --- /dev/null +++ b/test/components/swap/mock/staking.mock.ride @@ -0,0 +1,39 @@ +{-# STDLIB_VERSION 5 #-} +{-# CONTENT_TYPE DAPP #-} +{-# SCRIPT_TYPE ACCOUNT #-} + +@Callable(i) +func stake() = { + (nil, unit) +} + +@Callable(i) +func unstake(lpAssetIdStr: String, amount: Int) = { + let lpAssetId = lpAssetIdStr.fromBase58String() + ( + [ + ScriptTransfer(i.caller, amount, lpAssetId) + ], + unit + ) +} + +@Callable(i) +func unstakeINTERNAL( + lpAssetId: ByteVector, + amount: Int, + userAddress: ByteVector, + lpAssetRecipientAddress: ByteVector + ) = { + ( + [ + ScriptTransfer(Address(lpAssetRecipientAddress), amount, lpAssetId) + ], + unit + ) +} + +@Callable(i) +func stakeFor(userAddressStr: String) = { + (nil, unit) +} diff --git a/test/components/swap/swap.mjs b/test/components/swap/swap.mjs new file mode 100644 index 000000000..ee05e5dcb --- /dev/null +++ b/test/components/swap/swap.mjs @@ -0,0 +1,66 @@ +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import { address } from '@waves/ts-lib-crypto'; +import { invokeScript, nodeInteraction as ni } from '@waves/waves-transactions'; +import { create } from '@waves/node-api-js'; + +chai.use(chaiAsPromised); + +const apiBase = process.env.API_NODE_URL; +const chainId = 'R'; + +const api = create(apiBase); + +describe('swap: swap.mjs', /** @this {MochaSuiteModified} */ () => { + it('should successfully put with shouldAutoStake false', async function () { + const usdnAmount = 10e6; + const usdtAmount = 10e6; + const swapUsdnAmount = 1000; + const shouldAutoStake = false; + + const lpStable = address(this.accounts.lpStable, chainId); + const swap = address(this.accounts.swap, chainId); + + const put = invokeScript( + { + dApp: lpStable, + payment: [ + { assetId: this.usdtAssetId, amount: usdtAmount }, + { assetId: this.usdnAssetId, amount: usdnAmount }, + ], + call: { + function: 'put', + args: [ + { type: 'integer', value: 0 }, + { type: 'boolean', value: shouldAutoStake }, + ], + }, + chainId, + }, + this.accounts.user1, + ); + await api.transactions.broadcast(put, {}); + await ni.waitForTx(put.id, { apiBase }); + + const swapTx = invokeScript( + { + dApp: swap, + payment: [{ assetId: this.usdtAssetId, amount: usdtAmount }], + call: { + function: 'swap', + args: [ + { type: 'integer', value: swapUsdnAmount }, + { type: 'string', value: this.usdnAssetId }, + { type: 'string', value: address(this.accounts.user1, chainId) }, + ], + }, + chainId, + }, + this.accounts.user1, + ); + await api.transactions.broadcast(swapTx, {}); + await ni.waitForTx(swapTx.id, { apiBase }); + + // TODO: check swap result + }); +}); diff --git a/test/components/swap/swapReadonly.mjs b/test/components/swap/swapReadonly.mjs new file mode 100644 index 000000000..c4c46261d --- /dev/null +++ b/test/components/swap/swapReadonly.mjs @@ -0,0 +1,48 @@ +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import { address } from '@waves/ts-lib-crypto'; +import { invokeScript, nodeInteraction as ni } from '@waves/waves-transactions'; +import { create } from '@waves/node-api-js'; + +chai.use(chaiAsPromised); + +const apiBase = process.env.API_NODE_URL; +const chainId = 'R'; + +const api = create(apiBase); + +describe('swap: swapReadonly.mjs', /** @this {MochaSuiteModified} */() => { + it('should successfully put with shouldAutoStake false', async function () { + const usdnAmount = 10e6; + const usdtAmount = 10e6; + const swapUsdnAmount = 1000; + const shouldAutoStake = false; + + const lpStable = address(this.accounts.lpStable, chainId); + const swap = address(this.accounts.swap, chainId); + + const put = invokeScript({ + dApp: lpStable, + payment: [ + { assetId: this.usdtAssetId, amount: usdtAmount }, + { assetId: this.usdnAssetId, amount: usdnAmount }, + ], + call: { + function: 'put', + args: [ + { type: 'integer', value: 0 }, + { type: 'boolean', value: shouldAutoStake }, + ], + }, + chainId, + }, this.accounts.user1); + await api.transactions.broadcast(put, {}); + await ni.waitForTx(put.id, { apiBase }); + + const expr = `swapCalculateREADONLY(${swapUsdnAmount}, \"${this.usdtAssetId}\", \"${this.usdnAssetId}\")`; /* eslint-disable-line */ + const response = await api.utils.fetchEvaluate(swap, expr); + const checkData = response.result.value._2.value; /* eslint-disable-line */ + + // TODO: check checkData + }); +});