diff options
author | Greg Hysen <greg.hysen@gmail.com> | 2018-12-01 08:43:04 +0800 |
---|---|---|
committer | Greg Hysen <greg.hysen@gmail.com> | 2018-12-19 05:36:05 +0800 |
commit | 9f68ac7bbecea109692d62d5555bac67e86c123a (patch) | |
tree | 8d0ad6eaaf08b6dbbd057173f531d2af63410565 | |
parent | 4e341582ae74d7ab1c52c4e888d72c0c1c78e890 (diff) | |
download | dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.tar dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.tar.gz dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.tar.bz2 dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.tar.lz dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.tar.xz dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.tar.zst dexon-sol-tools-9f68ac7bbecea109692d62d5555bac67e86c123a.zip |
Making progress on generalized forwarder
3 files changed, 99 insertions, 77 deletions
diff --git a/contracts/protocol/test/utils/exchange_wrapper.ts b/contracts/protocol/test/utils/exchange_wrapper.ts index cb6dce901..6106e78ca 100644 --- a/contracts/protocol/test/utils/exchange_wrapper.ts +++ b/contracts/protocol/test/utils/exchange_wrapper.ts @@ -214,6 +214,7 @@ export class ExchangeWrapper { { from }, ); const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); + console.log(JSON.stringify(tx)); return tx; } public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> { diff --git a/packages/contracts/contracts/extensions/CompliantForwarder/CompliantForwarder.sol b/packages/contracts/contracts/extensions/CompliantForwarder/CompliantForwarder.sol index b8ba43b15..739f55024 100644 --- a/packages/contracts/contracts/extensions/CompliantForwarder/CompliantForwarder.sol +++ b/packages/contracts/contracts/extensions/CompliantForwarder/CompliantForwarder.sol @@ -22,16 +22,20 @@ pragma experimental ABIEncoderV2; import "../../protocol/Exchange/interfaces/IExchange.sol"; import "../../tokens/ERC721Token/IERC721Token.sol"; import "../../utils/LibBytes/LibBytes.sol"; +import "../../utils/ExchangeSelectors/ExchangeSelectors.sol"; -contract CompliantForwarder { +contract CompliantForwarder is ExchangeSelectors{ using LibBytes for bytes; - bytes4 constant internal EXCHANGE_FILL_ORDER_SELECTOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)")); IExchange internal EXCHANGE; IERC721Token internal COMPLIANCE_TOKEN; - bytes4 constant internal EXCHANGE_FILL_ORDER_SELECTOR_2 = 0xb4be83d5; + event ValidatedAddresses ( + bytes32 selector, + address one, + address[] addresses + ); constructor(address exchange, address complianceToken) public @@ -49,84 +53,94 @@ contract CompliantForwarder { external { // Validate `signedFillOrderTransaction` - bytes4 selector = signedExchangeTransaction.readBytes4(0); - address makerAddress = 0x00; + address[] memory validatedAddresses; + bytes32 selectorS; + address one; assembly { - function getMakerAddress(orderPtr) -> makerAddress { - let orderOffset := calldataload(orderPtr) - makerAddress := calldataload(orderOffset) + // Adds address to validate + function addAddressToValidate(addressToValidate) { + // Compute `addressesToValidate` memory location + let addressesToValidate_ := mload(0x40) + let nAddressesToValidate_ := mload(addressesToValidate_) + + // Increment length + nAddressesToValidate_ := add(mload(addressesToValidate_), 1) + mstore(addressesToValidate_, nAddressesToValidate_) + + // Append address to validate + let offset := mul(32, nAddressesToValidate_) + mstore(add(addressesToValidate_, offset), addressToValidate) } - switch selector - case 0xb4be83d500000000000000000000000000000000000000000000000000000000 { + function appendMakerAddressFromOrder(paramIndex) -> makerAddress { let exchangeTxPtr := calldataload(0x44) - // Add 0x20 for length offset and 0x04 for selector offset let orderPtrRelativeToExchangeTx := calldataload(add(0x4, add(exchangeTxPtr, 0x24))) // 0x60 let orderPtr := add(0x4,add(exchangeTxPtr, add(0x24, orderPtrRelativeToExchangeTx))) - makerAddress := calldataload(orderPtr) - - - //makerAddress := getMakerAddress(orderPtr) + addAddressToValidate(makerAddress) + } + + + // Extract addresses to validate + let exchangeTxPtr1 := calldataload(0x44) + let selector := and(calldataload(add(0x4, add(0x20, exchangeTxPtr1))), 0xffffffff00000000000000000000000000000000000000000000000000000000) + switch selector + case 0x097bb70b00000000000000000000000000000000000000000000000000000000 /* batchFillOrders */ + { + + } + case 0x3c28d86100000000000000000000000000000000000000000000000000000000 /* matchOrders */ + { + + } + case 0xb4be83d500000000000000000000000000000000000000000000000000000000 /* fillOrder */ + { + one := appendMakerAddressFromOrder(0) + //appendSignerAddress() } + case 0xd46b02c300000000000000000000000000000000000000000000000000000000 /* cancelOrder */ {} default { - // revert(0, 100) + revert(0, 100) } + + let addressesToValidate := mload(0x40) + let nAddressesToValidate := mload(addressesToValidate) + let newMemFreePtr := add(addressesToValidate, add(0x20, mul(mload(addressesToValidate), 0x20))) + mstore(0x40, newMemFreePtr) + + // Validate addresses + /* + let complianceTokenAddress := sload(COMPLIANCE_TOKEN_slot) + for {let i := add(32, mload(addressesToValidate))} lt(i, add(addressesToValidate, add(32, mul(nAddressesToValidate, 32)))) {i := add(i, 32)} { + // call `COMPLIANCE_TOKEN.balanceOf` + let success := call( + gas, // forward all gas + complianceTokenAddress, // call address of asset proxy + 0, // don't send any ETH + i, // pointer to start of input + 32, // length of input (one padded address) + 0, // write output over memory that won't be reused + 0 // don't copy output to memory + ) + if eq(success, 0) { + revert(0, 100) + } + }*/ + + validatedAddresses := addressesToValidate + selectorS := selector } - - /* - if (selector != 0xb4be83d5) { - revert("EXCHANGE_TRANSACTION_NOT_FILL_ORDER"); - }*/ - - // Taker must be compliant - require( - COMPLIANCE_TOKEN.balanceOf(signerAddress) > 0, - "TAKER_UNVERIFIED" - ); - - // Extract maker address from fill order transaction and ensure maker is compliant - // Below is the table of calldata offsets into a fillOrder transaction. - /** - ### parameters - 0x00 ptr<order> - 0x20 takerAssetFillAmount - 0x40 ptr<signature> - ### order - 0x60 makerAddress - 0x80 takerAddress - 0xa0 feeRecipientAddress - 0xc0 senderAddress - 0xe0 makerAssetAmount - 0x100 takerAssetAmount - 0x120 makerFee - 0x140 takerFee - 0x160 expirationTimeSeconds - 0x180 salt - 0x1a0 ptr<makerAssetData> - 0x1c0 ptr<takerAssetData> - 0x1e0 makerAssetData - * takerAssetData - * signature - ------------------------------ - * Context-dependent offsets; unknown at compile time. - */ - // Add 0x4 to a given offset to account for the fillOrder selector prepended to `signedFillOrderTransaction`. - // Add 0xc to the makerAddress since abi-encoded addresses are left padded with 12 bytes. - // Putting this together: makerAddress = 0x60 + 0x4 + 0xc = 0x70 - //address makerAddress = signedExchangeTransaction.readAddress(0x70); - require( - COMPLIANCE_TOKEN.balanceOf(makerAddress) > 0, - "MAKER_UNVERIFIED" - ); + + emit ValidatedAddresses(selectorS, one, validatedAddresses); // All entities are verified. Execute fillOrder. + /* EXCHANGE.executeTransaction( salt, signerAddress, signedExchangeTransaction, signature - ); + );*/ } }
\ No newline at end of file diff --git a/packages/contracts/test/extensions/compliant_forwarder.ts b/packages/contracts/test/extensions/compliant_forwarder.ts index b916f54c9..4eedffe05 100644 --- a/packages/contracts/test/extensions/compliant_forwarder.ts +++ b/packages/contracts/test/extensions/compliant_forwarder.ts @@ -5,6 +5,7 @@ import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as chai from 'chai'; import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; import { ExchangeContract } from '../../generated-wrappers/exchange'; @@ -26,8 +27,10 @@ import { TransactionFactory } from '../utils/transaction_factory'; import { ContractName, ERC20BalancesByOwner, SignedTransaction } from '../utils/types'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; -import { MethodAbi } from 'ethereum-types'; +import { MethodAbi, AbiDefinition } from 'ethereum-types'; import { AbiEncoder } from '@0x/utils'; +import { Method } from '@0x/utils/lib/src/abi_encoder'; +import { LogDecoder } from '../utils/log_decoder'; chaiSetup.configure(); const expect = chai.expect; @@ -184,6 +187,18 @@ describe.only(ContractName.CompliantForwarder, () => { compliantSignedFillOrderTx = takerTransactionFactory.newSignedTransaction( compliantSignedOrderWithoutExchangeAddressData, ); + + /* generate selectors for every exchange method + _.each(exchangeInstance.abi, (abiDefinition: AbiDefinition) => { + try { + const method = new Method(abiDefinition as MethodAbi); + console.log('\n', `// ${method.getDataItem().name}`); + console.log(`bytes4 constant ${method.getDataItem().name}Selector = ${method.getSelector()};`); + console.log(`bytes4 constant ${method.getDataItem().name}SelectorGenerator = byes4(keccak256('${method.getSignature()}'));`); + } catch(e) { + _.noop(); + } + });*/ }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -196,23 +211,15 @@ describe.only(ContractName.CompliantForwarder, () => { erc20Balances = await erc20Wrapper.getBalancesAsync(); }); it.only('should transfer the correct amounts when maker and taker are compliant', async () => { - - - const method = new AbiEncoder.Method(compliantForwarderInstance.abi[0] as MethodAbi); - const args = [ - compliantSignedFillOrderTx.salt, - compliantSignedFillOrderTx.signerAddress, - compliantSignedFillOrderTx.data, - compliantSignedFillOrderTx.signature - ]; - console.log(method.encode(args, {annotate: true})); - - await compliantForwarderInstance.executeTransaction.sendTransactionAsync( + const txHash = await compliantForwarderInstance.executeTransaction.sendTransactionAsync( compliantSignedFillOrderTx.salt, compliantSignedFillOrderTx.signerAddress, compliantSignedFillOrderTx.data, compliantSignedFillOrderTx.signature, ); + const decoder = new LogDecoder(web3Wrapper); + const tx = await decoder.getTxWithDecodedLogsAsync(txHash); + console.log(JSON.stringify(tx, null, 4)); const newBalances = await erc20Wrapper.getBalancesAsync(); const makerAssetFillAmount = takerAssetFillAmount .times(compliantSignedOrder.makerAssetAmount) @@ -298,7 +305,7 @@ describe.only(ContractName.CompliantForwarder, () => { RevertReason.TakerUnverified ); }); - it('should revert if maker address is not compliant (does not hold a Yes Token)', async () => { + it.only('should revert if maker address is not compliant (does not hold a Yes Token)', async () => { // Create signed order with non-compliant maker address const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ senderAddress: compliantForwarderInstance.address, |