diff --git a/src/concrete/ob/OrderBook.sol b/src/concrete/ob/OrderBook.sol index 2be364306..b14e4d4aa 100644 --- a/src/concrete/ob/OrderBook.sol +++ b/src/concrete/ob/OrderBook.sol @@ -747,25 +747,30 @@ contract OrderBook is IOrderBookV4, IMetaV1_2, ReentrancyGuard, Multicall, Order uint256(orderHash), uint256(uint160(order.owner)), uint256(uint160(counterparty)) ); - callingContext[CONTEXT_VAULT_INPUTS_COLUMN - 1] = LibUint256Array.arrayFrom( - uint256(uint160(order.validInputs[inputIOIndex].token)), - order.validInputs[inputIOIndex].decimals, - order.validInputs[inputIOIndex].vaultId, - sVaultBalances[order.owner][order.validInputs[inputIOIndex].token][order.validInputs[inputIOIndex] - .vaultId], - // Don't know the balance diff yet! - 0 - ); + { + callingContext[CONTEXT_VAULT_INPUTS_COLUMN - 1] = LibUint256Array.arrayFrom( + uint256(uint160(order.validInputs[inputIOIndex].token)), + order.validInputs[inputIOIndex].decimals * 1e18, + order.validInputs[inputIOIndex].vaultId, + sVaultBalances[order.owner][order.validInputs[inputIOIndex].token][order.validInputs[inputIOIndex] + .vaultId], + // Don't know the balance diff yet! + 0 + ); + } + + { + callingContext[CONTEXT_VAULT_OUTPUTS_COLUMN - 1] = LibUint256Array.arrayFrom( + uint256(uint160(order.validOutputs[outputIOIndex].token)), + order.validOutputs[outputIOIndex].decimals * 1e18, + order.validOutputs[outputIOIndex].vaultId, + sVaultBalances[order.owner][order.validOutputs[outputIOIndex].token][order.validOutputs[outputIOIndex] + .vaultId], + // Don't know the balance diff yet! + 0 + ); + } - callingContext[CONTEXT_VAULT_OUTPUTS_COLUMN - 1] = LibUint256Array.arrayFrom( - uint256(uint160(order.validOutputs[outputIOIndex].token)), - order.validOutputs[outputIOIndex].decimals, - order.validOutputs[outputIOIndex].vaultId, - sVaultBalances[order.owner][order.validOutputs[outputIOIndex].token][order.validOutputs[outputIOIndex] - .vaultId], - // Don't know the balance diff yet! - 0 - ); context = LibContext.build(callingContext, signedContext); } diff --git a/test/concrete/ob/OrderBook.quote.t.sol b/test/concrete/ob/OrderBook.quote.t.sol index 357a70e80..701150119 100644 --- a/test/concrete/ob/OrderBook.quote.t.sol +++ b/test/concrete/ob/OrderBook.quote.t.sol @@ -12,9 +12,14 @@ import { } from "rain.orderbook.interface/interface/IOrderBookV4.sol"; import {LibTestAddOrder} from "test/util/lib/LibTestAddOrder.sol"; import {IERC20} from "forge-std/interfaces/IERC20.sol"; +import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; + +import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; /// @title OrderBookQuoteTest contract OrderBookQuoteTest is OrderBookExternalRealTest { + using Strings for address; + /// Dead orders always eval to false. function testQuoteDeadOrder(Quote memory quoteConfig) external view { (bool success, uint256 maxOutput, uint256 ioRatio) = iOrderbook.quote(quoteConfig); @@ -36,7 +41,8 @@ contract OrderBookQuoteTest is OrderBookExternalRealTest { config.validOutputs[0].token = address(iToken0); config.validOutputs[0].decimals = 18; config.validInputs[0].token = address(iToken1); - config.validInputs[0].decimals = 18; + config.validInputs[0].decimals = 6; + vm.mockCall(address(iToken1), abi.encodeWithSelector(IERC20Metadata.decimals.selector), abi.encode(6)); vm.mockCall( address(iToken0), @@ -105,6 +111,8 @@ contract OrderBookQuoteTest is OrderBookExternalRealTest { function testQuoteContextSender(address owner, OrderConfigV3 memory config, uint256 depositAmount) external { depositAmount = bound(depositAmount, 1e18, type(uint256).max); + string memory usingWordsFrom = string.concat("using-words-from ", address(iSubParser).toHexString(), "\n"); + bytes[] memory rainlang = new bytes[](10); // quote msg.sender rainlang[0] = "_ _:1 context<0 0>();:;"; @@ -120,8 +128,15 @@ contract OrderBookQuoteTest is OrderBookExternalRealTest { // inputs // vault input token rainlang[4] = "_ _:1 context<3 0>();:;"; - // vault io token decimals - rainlang[5] = "_ _:1 context<3 1>();:;"; + // vault input token decimals + rainlang[5] = bytes( + string.concat( + usingWordsFrom, + ":ensure(equal-to(input-token-decimals() context<3 1>()) \"input decimals\"),", + ":ensure(equal-to(input-token-decimals() 6) \"input decimals literal\"),", + "_ _:1 context<3 1>();:;" + ) + ); // vault io vault id // not easy to test with this setup // rainlang[6] = "_ _:1 context<3 2>();:;"; @@ -130,8 +145,15 @@ contract OrderBookQuoteTest is OrderBookExternalRealTest { // outputs // vault output token rainlang[7] = "_ _:1 context<4 0>();:;"; - // vault io token decimals - rainlang[8] = "_ _:1 context<4 1>();:;"; + // vault output token decimals + rainlang[8] = bytes( + string.concat( + usingWordsFrom, + ":ensure(equal-to(output-token-decimals() context<4 1>()) \"output decimals\"),", + ":ensure(equal-to(output-token-decimals() 18) \"output decimals literal\"),", + "_ _:1 context<4 1>();:;" + ) + ); // vault io vault id // not easy to test with this setup // rainlang[9] = "_ _:1 context<4 2>();:;"; @@ -156,10 +178,11 @@ contract OrderBookQuoteTest is OrderBookExternalRealTest { expectedIoRatio[2] = uint256(uint160(owner)); expectedIoRatio[3] = uint256(uint160(address(this))); expectedIoRatio[4] = uint256(uint160(address(iToken1))); - expectedIoRatio[5] = 18; + // Input decimals scaled to 18 fixed point value. + expectedIoRatio[5] = 6e18; expectedIoRatio[6] = 0; expectedIoRatio[7] = uint256(uint160(address(iToken0))); - expectedIoRatio[8] = 18; + expectedIoRatio[8] = 18e18; expectedIoRatio[9] = depositAmount; checkQuote(owner, config, rainlang, depositAmount, expectedMaxOutput, expectedIoRatio);