From 420d03a0b88178e73724b686fbade80a92ec9912 Mon Sep 17 00:00:00 2001 From: Lopes Date: Thu, 22 Aug 2024 15:33:58 -0300 Subject: [PATCH] CU-86drvz6jc Swap Multi Invoke - Implement routes definitions to Swap Controller --- .../CU-86drvz6jc-4_2024-08-22-18-33.json | 10 + .../FlamingoSwapInvocationBuilderNeo3.spec.ts | 205 ++++++++++++++++++ .../FlamingoSwapInvocationBuilderNeo3.ts | 41 ++-- .../bs-neo3/src/helpers/FlamingoSwapHelper.ts | 6 + 4 files changed, 249 insertions(+), 13 deletions(-) create mode 100644 common/changes/@cityofzion/bs-neo3/CU-86drvz6jc-4_2024-08-22-18-33.json create mode 100644 packages/bs-neo3/src/__tests__/builder/invocation/FlamingoSwapInvocationBuilderNeo3.spec.ts diff --git a/common/changes/@cityofzion/bs-neo3/CU-86drvz6jc-4_2024-08-22-18-33.json b/common/changes/@cityofzion/bs-neo3/CU-86drvz6jc-4_2024-08-22-18-33.json new file mode 100644 index 0000000..c5a6819 --- /dev/null +++ b/common/changes/@cityofzion/bs-neo3/CU-86drvz6jc-4_2024-08-22-18-33.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@cityofzion/bs-neo3", + "comment": "Fixing NEO implementation", + "type": "patch" + } + ], + "packageName": "@cityofzion/bs-neo3" +} \ No newline at end of file diff --git a/packages/bs-neo3/src/__tests__/builder/invocation/FlamingoSwapInvocationBuilderNeo3.spec.ts b/packages/bs-neo3/src/__tests__/builder/invocation/FlamingoSwapInvocationBuilderNeo3.spec.ts new file mode 100644 index 0000000..96b0083 --- /dev/null +++ b/packages/bs-neo3/src/__tests__/builder/invocation/FlamingoSwapInvocationBuilderNeo3.spec.ts @@ -0,0 +1,205 @@ +import { Network, SwapServiceSwapToReceiveArgs, SwapServiceSwapToUseArgs } from '@cityofzion/blockchain-service' +import { ContractInvocationMulti } from '@cityofzion/neon-dappkit-types' +import { FlamingoSwapInvocationBuilderNeo3 } from '../../../builder/invocation/FlamingoSwapInvocationBuilderNeo3' +import { FlamingoSwapConstants } from '../../../constants/FlamingoSwapConstants' +import { BSNeo3Helper, BSNeo3NetworkId } from '../../../helpers/BSNeo3Helper' + +let network: Network + +describe('FlamingoSwapInvocationBuilderNeo3', () => { + beforeEach(() => { + network = BSNeo3Helper.DEFAULT_NETWORK + }) + + it('Should match the invocation script swapping NEO to GAS - swapTokenToUse', () => { + const NEO = FlamingoSwapConstants.FLAMINGO_SWAP_TOKENS[network.id]['NEO'] + const bNEO = FlamingoSwapConstants.FLAMINGO_SWAP_TOKENS[network.id]['bNEO'] + const GAS = FlamingoSwapConstants.FLAMINGO_SWAP_TOKENS[network.id]['GAS'] + + const data: SwapServiceSwapToUseArgs = { + address: 'address', + amountToUse: '2', + deadline: '10', + minimumReceived: '5.98684835', + network, + routePath: [NEO, bNEO, GAS], + type: 'swapTokenToUse', + } + + const response = FlamingoSwapInvocationBuilderNeo3.swapInvocation(data) + + const expectedResponse: ContractInvocationMulti = { + invocations: [ + { + scriptHash: '0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5', + operation: 'transfer', + args: [ + { + type: 'Hash160', + value: data.address, + }, + { + type: 'Hash160', + value: '0x48c40d4666f93408be1bef038b6722404d9a4c2a', + }, + { + type: 'Integer', + value: '2', + }, + { + type: 'Any', + value: null, + }, + ], + }, + { + scriptHash: '0xf970f4ccecd765b63732b821775dc38c25d74f23', + operation: 'swapTokenInForTokenOut', + args: [ + { + type: 'Hash160', + value: data.address, + }, + { + type: 'Integer', + value: '200000000', + }, + { + type: 'Integer', + value: '598684835', + }, + { + type: 'Array', + value: [ + { + type: 'Hash160', + value: '0x48c40d4666f93408be1bef038b6722404d9a4c2a', + }, + { + type: 'Hash160', + value: '0xd2a4cff31913016155e38e474a2c06d08be276cf', + }, + ], + }, + { + type: 'Integer', + value: expect.any(String), + }, + ], + }, + ], + signers: [ + { + scopes: 16, + allowedContracts: [ + '0x3244fcadcccff190c329f7b3083e4da2af60fbce', + '0xf970f4ccecd765b63732b821775dc38c25d74f23', + '0xca2d20610d7982ebe0bed124ee7e9b2d580a6efc', + '0xfb75a5314069b56e136713d38477f647a13991b4', + '0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5', + '0x48c40d4666f93408be1bef038b6722404d9a4c2a', + '0xd2a4cff31913016155e38e474a2c06d08be276cf', + ], + }, + ], + } + + expect(response).toEqual(expectedResponse) + }) + + it('Should match the invocation script swapping GAS to NEO - swapTokenToReceive', () => { + const NEO = FlamingoSwapConstants.FLAMINGO_SWAP_TOKENS[network.id]['NEO'] + const bNEO = FlamingoSwapConstants.FLAMINGO_SWAP_TOKENS[network.id]['bNEO'] + const GAS = FlamingoSwapConstants.FLAMINGO_SWAP_TOKENS[network.id]['GAS'] + + const data: SwapServiceSwapToReceiveArgs = { + address: 'address', + amountToReceive: '1', + deadline: '10', + maximumSelling: '3.04188283', + network, + routePath: [GAS, bNEO, NEO], + type: 'swapTokenToReceive', + } + + const response = FlamingoSwapInvocationBuilderNeo3.swapInvocation(data) + + const expectedResponse: ContractInvocationMulti = { + invocations: [ + { + scriptHash: '0xf970f4ccecd765b63732b821775dc38c25d74f23', + operation: 'swapTokenOutForTokenIn', + args: [ + { + type: 'Hash160', + value: data.address, + }, + { + type: 'Integer', + value: '100000000', + }, + { + type: 'Integer', + value: '304188283', + }, + { + type: 'Array', + value: [ + { + type: 'Hash160', + value: '0xd2a4cff31913016155e38e474a2c06d08be276cf', + }, + { + type: 'Hash160', + value: '0x48c40d4666f93408be1bef038b6722404d9a4c2a', + }, + ], + }, + { + type: 'Integer', + value: expect.any(String), + }, + ], + }, + { + scriptHash: '0xd2a4cff31913016155e38e474a2c06d08be276cf', + operation: 'transfer', + args: [ + { + type: 'Hash160', + value: data.address, + }, + { + type: 'Hash160', + value: '0x48c40d4666f93408be1bef038b6722404d9a4c2a', + }, + { + type: 'Integer', + value: '100000', + }, + { + type: 'Any', + value: null, + }, + ], + }, + ], + signers: [ + { + scopes: 16, + allowedContracts: [ + '0xf970f4ccecd765b63732b821775dc38c25d74f23', + '0xca2d20610d7982ebe0bed124ee7e9b2d580a6efc', + '0xfb75a5314069b56e136713d38477f647a13991b4', + '0xd2a4cff31913016155e38e474a2c06d08be276cf', + '0x48c40d4666f93408be1bef038b6722404d9a4c2a', + '0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5', + '0x3244fcadcccff190c329f7b3083e4da2af60fbce', + ], + }, + ], + } + + expect(response).toEqual(expectedResponse) + }) +}) diff --git a/packages/bs-neo3/src/builder/invocation/FlamingoSwapInvocationBuilderNeo3.ts b/packages/bs-neo3/src/builder/invocation/FlamingoSwapInvocationBuilderNeo3.ts index 9fa2191..3f8e955 100644 --- a/packages/bs-neo3/src/builder/invocation/FlamingoSwapInvocationBuilderNeo3.ts +++ b/packages/bs-neo3/src/builder/invocation/FlamingoSwapInvocationBuilderNeo3.ts @@ -27,10 +27,12 @@ export class FlamingoSwapInvocationBuilderNeo3 { const tokenToReceive = routePath[routePath.length - 1] const scriptHashes = FlamingoSwapHelper.getFlamingoSwapScriptHashes(network) - const tokenToReceiveOverrode = FlamingoSwapHelper.overrideToken(network, tokenToReceive) const invocations: ContractInvocation[] = [] - const allowedContracts = this.#getAllowedContracts(scriptHashes, routePath) + const allowedContracts: string[] = [] + + const tokenToReceiveOverrode = FlamingoSwapHelper.overrideToken(network, tokenToReceive) + const routePathOverrode = FlamingoSwapHelper.overrideRoutePath(network, routePath) const amountToReceiveFormatted = FlamingoSwapHelper.formatAmount(amountToReceive, tokenToReceiveOverrode.decimals) const maximumSellingFormatted = FlamingoSwapHelper.formatAmount(maximumSelling, tokenToUse.decimals) @@ -41,19 +43,22 @@ export class FlamingoSwapInvocationBuilderNeo3 { amountToReceive: amountToReceiveFormatted, maximumSelling: maximumSellingFormatted, deadline, - args: this.#mapRoutePathToArgs(routePath), + args: this.#mapRoutePathToArgs(routePathOverrode), }) invocations.push(swapInvocation) + allowedContracts.push(...this.#getAllowedContracts(scriptHashes, routePath)) if (FlamingoSwapHelper.isNeoToken(network, tokenToReceive)) { const amountToReceiveTransfer = u.BigInteger.fromNumber( Number(amountToReceiveFormatted) * FlamingoSwapConstants.GAS_PER_NEO ).toString() - const neoTransferInvocation = this.#buildNEOTransferInvocation(address, amountToReceiveTransfer, network) + const gasHash = FlamingoSwapHelper.getFlamingoSwapToken(network, 'GAS').hash + const neoTransferInvocation = this.#buildNEOTransferInvocation(address, gasHash, amountToReceiveTransfer, network) invocations.push(neoTransferInvocation) + allowedContracts.push(FlamingoSwapHelper.getFlamingoSwapPool(network, 'FLP-bNEO-GAS').hash) } return { @@ -76,15 +81,20 @@ export class FlamingoSwapInvocationBuilderNeo3 { const scriptHashes = FlamingoSwapHelper.getFlamingoSwapScriptHashes(network) const invocations: ContractInvocation[] = [] - const allowedContracts = this.#getAllowedContracts(scriptHashes, routePath) + const allowedContracts: string[] = [] if (FlamingoSwapHelper.isNeoToken(network, tokenToUse)) { - const neoTransferInvocation = this.#buildNEOTransferInvocation(address, amountToUse, network) + const neoHash = FlamingoSwapHelper.getFlamingoSwapToken(network, 'NEO').hash + const neoTransferInvocation = this.#buildNEOTransferInvocation(address, neoHash, amountToUse, network) invocations.push(neoTransferInvocation) + allowedContracts.push(FlamingoSwapHelper.getFlamingoSwapPool(network, 'FLP-bNEO-GAS').hash) } - const amountToUseFormatted = FlamingoSwapHelper.formatAmount(amountToUse, tokenToUse.decimals) + const tokenToUseOverrode = FlamingoSwapHelper.overrideToken(network, tokenToUse) + const routePathOverrode = FlamingoSwapHelper.overrideRoutePath(network, routePath) + + const amountToUseFormatted = FlamingoSwapHelper.formatAmount(amountToUse, tokenToUseOverrode.decimals) const minimumReceivedFormatted = FlamingoSwapHelper.formatAmount(minimumReceived, tokenToReceive.decimals) const swapInvocation = NeonDappKitInvocationBuilderNeo3.swapTokenInForTokenOutContractInvocation({ @@ -93,10 +103,11 @@ export class FlamingoSwapInvocationBuilderNeo3 { minimumReceived: minimumReceivedFormatted, senderAddress: address, deadline, - args: this.#mapRoutePathToArgs(routePath), + args: this.#mapRoutePathToArgs(routePathOverrode), }) invocations.push(swapInvocation) + allowedContracts.push(...this.#getAllowedContracts(scriptHashes, routePath)) return { invocations, @@ -120,15 +131,19 @@ export class FlamingoSwapInvocationBuilderNeo3 { ] } - static #buildNEOTransferInvocation(address: string, amount: string, network: Network): ContractInvocation { + static #buildNEOTransferInvocation( + senderAddress: string, + contractHash: string, + amount: string, + network: Network + ): ContractInvocation { const bNEO = FlamingoSwapHelper.getFlamingoSwapToken(network, 'bNEO') - const GAS = FlamingoSwapHelper.getFlamingoSwapToken(network, 'GAS') return NeonDappKitInvocationBuilderNeo3.transferContractInvocation({ - senderAddress: address, - amount, + contractHash, tokenHash: bNEO.hash, - contractHash: GAS.hash, + senderAddress, + amount, }) } } diff --git a/packages/bs-neo3/src/helpers/FlamingoSwapHelper.ts b/packages/bs-neo3/src/helpers/FlamingoSwapHelper.ts index 6c19ed2..ad7dd05 100644 --- a/packages/bs-neo3/src/helpers/FlamingoSwapHelper.ts +++ b/packages/bs-neo3/src/helpers/FlamingoSwapHelper.ts @@ -97,6 +97,12 @@ export class FlamingoSwapHelper { return overrodeRoute } + static overrideRoutePath(network: Network, routePath: Token[]): Token[] { + const overrodeRoutePath = routePath.map(token => this.overrideToken(network, token)) + + return overrodeRoutePath.filter((item, index, arr) => arr.indexOf(item) === index) + } + static normalizeHash(hash: string): string { return hash.startsWith('0x') ? hash.slice(2) : hash }