diff --git a/pkg/standalone-utils/contracts/relayer/VaultActions.sol b/pkg/standalone-utils/contracts/relayer/VaultActions.sol index 8fbbf19aae..b4fb999169 100644 --- a/pkg/standalone-utils/contracts/relayer/VaultActions.sol +++ b/pkg/standalone-utils/contracts/relayer/VaultActions.sol @@ -66,14 +66,14 @@ abstract contract VaultActions is IBaseRelayerLibrary { uint256 deadline, uint256 value, uint256 outputReference - ) external payable virtual { + ) external payable virtual returns (uint256 result) { require(funds.sender == msg.sender || funds.sender == address(this), "Incorrect sender"); if (_isChainedReference(singleSwap.amount)) { singleSwap.amount = _getChainedReferenceValue(singleSwap.amount); } - uint256 result = getVault().swap{ value: value }(singleSwap, funds, limit, deadline); + result = getVault().swap{ value: value }(singleSwap, funds, limit, deadline); if (_isChainedReference(outputReference)) { _setChainedReferenceValue(outputReference, result); @@ -89,7 +89,7 @@ abstract contract VaultActions is IBaseRelayerLibrary { uint256 deadline, uint256 value, OutputReference[] calldata outputReferences - ) external payable virtual { + ) external payable virtual returns (int256[] memory results) { require(funds.sender == msg.sender || funds.sender == address(this), "Incorrect sender"); for (uint256 i = 0; i < swaps.length; ++i) { @@ -99,7 +99,7 @@ abstract contract VaultActions is IBaseRelayerLibrary { } } - int256[] memory results = getVault().batchSwap{ value: value }(kind, swaps, assets, funds, limits, deadline); + results = getVault().batchSwap{ value: value }(kind, swaps, assets, funds, limits, deadline); for (uint256 i = 0; i < outputReferences.length; ++i) { require(_isChainedReference(outputReferences[i].key), "invalid chained reference"); diff --git a/pkg/standalone-utils/contracts/relayer/VaultQueryActions.sol b/pkg/standalone-utils/contracts/relayer/VaultQueryActions.sol index 7ee00ad8a1..0c3bf546b3 100644 --- a/pkg/standalone-utils/contracts/relayer/VaultQueryActions.sol +++ b/pkg/standalone-utils/contracts/relayer/VaultQueryActions.sol @@ -37,14 +37,14 @@ abstract contract VaultQueryActions is VaultActions { uint256, // deadline uint256, // value uint256 outputReference - ) external payable override { + ) external payable override returns (uint256 result) { require(funds.sender == msg.sender || funds.sender == address(this), "Incorrect sender"); if (_isChainedReference(singleSwap.amount)) { singleSwap.amount = _getChainedReferenceValue(singleSwap.amount); } - uint256 result = _querySwap(singleSwap, funds); + result = _querySwap(singleSwap, funds); _require(singleSwap.kind == IVault.SwapKind.GIVEN_IN ? result >= limit : result <= limit, Errors.SWAP_LIMIT); @@ -102,7 +102,7 @@ abstract contract VaultQueryActions is VaultActions { uint256, // deadline uint256, // value OutputReference[] calldata outputReferences - ) external payable override { + ) external payable override returns (int256[] memory results) { require(funds.sender == msg.sender || funds.sender == address(this), "Incorrect sender"); for (uint256 i = 0; i < swaps.length; ++i) { @@ -112,7 +112,7 @@ abstract contract VaultQueryActions is VaultActions { } } - int256[] memory results = getVault().queryBatchSwap(kind, swaps, assets, funds); + results = getVault().queryBatchSwap(kind, swaps, assets, funds); for (uint256 i = 0; i < outputReferences.length; ++i) { require(_isChainedReference(outputReferences[i].key), "invalid chained reference"); diff --git a/pkg/standalone-utils/test/VaultQueryActions.test.ts b/pkg/standalone-utils/test/VaultQueryActions.test.ts index 4e020e0378..481882dcd6 100644 --- a/pkg/standalone-utils/test/VaultQueryActions.test.ts +++ b/pkg/standalone-utils/test/VaultQueryActions.test.ts @@ -4,7 +4,7 @@ import { BigNumberish, FP_ZERO, fp } from '@balancer-labs/v2-helpers/src/numbers import TokenList from '@balancer-labs/v2-helpers/src/models/tokens/TokenList'; import WeightedPool from '@balancer-labs/v2-helpers/src/models/pools/weighted/WeightedPool'; import { SwapKind, UserBalanceOpKind, WeightedPoolEncoder } from '@balancer-labs/balancer-js'; -import { MAX_UINT112, randomAddress } from '@balancer-labs/v2-helpers/src/constants'; +import { MAX_UINT112, MAX_UINT256, randomAddress } from '@balancer-labs/v2-helpers/src/constants'; import { Contract, BigNumber } from 'ethers'; import { expect } from 'chai'; import { expectChainedReferenceContents, toChainedReference } from './helpers/chainedReferences'; @@ -22,6 +22,7 @@ import { import { sharedBeforeEach } from '@balancer-labs/v2-common/sharedBeforeEach'; import { deploy } from '@balancer-labs/v2-helpers/src/contract'; import { expectArrayEqualWithError } from '@balancer-labs/v2-helpers/src/test/relativeError'; +import { defaultAbiCoder } from 'ethers/lib/utils'; describe('VaultQueryActions', function () { const INITIAL_BALANCE = fp(1000); @@ -104,39 +105,60 @@ describe('VaultQueryActions', function () { }); function itTestsSimpleSwap() { - it('stores swap output as chained reference', async () => { - const expectedAmountOut = await queries.querySwap( - { - poolId: poolIdA, - kind: SwapKind.GivenIn, - assetIn: tokens.DAI.address, - assetOut: tokens.MKR.address, - amount: amountIn, - userData: '0x', - }, - { - sender: TypesConverter.toAddress(sender), - recipient: TypesConverter.toAddress(recipient), - fromInternalBalance: false, - toInternalBalance: false, - } - ); + describe('simple swap', () => { + let expectedAmountOut: BigNumber; - await ( - await relayer.connect(user).vaultActionsQueryMulticall([ + sharedBeforeEach('get expected amount out', async () => { + expectedAmountOut = await queries.querySwap( + { + poolId: poolIdA, + kind: SwapKind.GivenIn, + assetIn: tokens.DAI.address, + assetOut: tokens.MKR.address, + amount: amountIn, + userData: '0x', + }, + { + sender: TypesConverter.toAddress(sender), + recipient: TypesConverter.toAddress(recipient), + fromInternalBalance: false, + toInternalBalance: false, + } + ); + }); + + it('stores swap output as chained reference', async () => { + await ( + await relayer.connect(user).vaultActionsQueryMulticall([ + encodeSwap(relayerLibrary, { + poolId: poolIdA, + tokenIn: tokens.DAI, + tokenOut: tokens.MKR, + amount: amountIn, + outputReference: toChainedReference(0), + sender, + recipient, + }), + ]) + ).wait(); + + await expectChainedReferenceContents(relayer, toChainedReference(0), expectedAmountOut); + }); + + it('returns the swap output directly', async () => { + const [actualAmountOut] = await relayer.connect(user).callStatic.vaultActionsQueryMulticall([ encodeSwap(relayerLibrary, { poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount: amountIn, - outputReference: toChainedReference(0), sender, recipient, }), - ]) - ).wait(); + ]); - await expectChainedReferenceContents(relayer, toChainedReference(0), expectedAmountOut); + expect(actualAmountOut).to.equal(expectedAmountOut); + }); }); } }); @@ -184,40 +206,78 @@ describe('VaultQueryActions', function () { }); function itTestsBatchSwap() { - it('stores batch swap output as chained reference', async () => { + describe('batch swap', () => { const amount = fp(1); - const indexIn = tokens.indexOf(tokens.DAI); - const indexOut = tokens.indexOf(tokens.MKR); - - const result = await queries.queryBatchSwap( - SwapKind.GivenIn, - [{ poolId: poolIdA, assetInIndex: indexIn, assetOutIndex: indexOut, amount, userData: '0x' }], - tokens.addresses, - { - sender: TypesConverter.toAddress(sender), - recipient, - fromInternalBalance: false, - toInternalBalance: false, - } - ); - expect(result[indexIn]).to.deep.equal(amount); - const expectedAmountOut = result[indexOut].mul(-1); + it('stores batch swap output as chained reference', async () => { + const indexIn = tokens.indexOf(tokens.DAI); + const indexOut = tokens.indexOf(tokens.MKR); - await ( - await relayer.connect(user).vaultActionsQueryMulticall([ + const result = await queries.queryBatchSwap( + SwapKind.GivenIn, + [{ poolId: poolIdA, assetInIndex: indexIn, assetOutIndex: indexOut, amount, userData: '0x' }], + tokens.addresses, + { + sender: TypesConverter.toAddress(sender), + recipient, + fromInternalBalance: false, + toInternalBalance: false, + } + ); + + expect(result[indexIn]).to.deep.equal(amount); + const expectedAmountOut = result[indexOut].mul(-1); + + await ( + await relayer.connect(user).vaultActionsQueryMulticall([ + encodeBatchSwap({ + relayerLibrary, + tokens, + swaps: [{ poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount }], + sender, + recipient, + outputReferences: { MKR: toChainedReference(0) }, + }), + ]) + ).wait(); + + await expectChainedReferenceContents(relayer, toChainedReference(0), expectedAmountOut); + }); + + it('stores batch swap output directly', async () => { + const indexIn = tokens.indexOf(tokens.DAI); + const indexOut = tokens.indexOf(tokens.MKR); + + const result = await queries.queryBatchSwap( + SwapKind.GivenIn, + [{ poolId: poolIdA, assetInIndex: indexIn, assetOutIndex: indexOut, amount, userData: '0x' }], + tokens.addresses, + { + sender: TypesConverter.toAddress(sender), + recipient, + fromInternalBalance: false, + toInternalBalance: false, + } + ); + + expect(result[indexIn]).to.deep.equal(amount); + const expectedAmountOut = result[indexOut].mul(-1); + + const [encodedResult] = await relayer.connect(user).callStatic.vaultActionsQueryMulticall([ encodeBatchSwap({ relayerLibrary, tokens, swaps: [{ poolId: poolIdA, tokenIn: tokens.DAI, tokenOut: tokens.MKR, amount }], sender, recipient, - outputReferences: { MKR: toChainedReference(0) }, }), - ]) - ).wait(); + ]); - await expectChainedReferenceContents(relayer, toChainedReference(0), expectedAmountOut); + const [actualResult] = defaultAbiCoder.decode(['uint256[]'], encodedResult); + const actualAmountOut = MAX_UINT256.sub(actualResult[indexOut]); + + expect(actualAmountOut).to.almostEqual(expectedAmountOut); + }); }); } });