Making progress on generalized forwarder
This commit is contained in:
parent
4e341582ae
commit
9f68ac7bbe
@ -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> {
|
||||
|
@ -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)
|
||||
}
|
||||
default {
|
||||
// revert(0, 100)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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"
|
||||
);
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
emit ValidatedAddresses(selectorS, one, validatedAddresses);
|
||||
|
||||
// All entities are verified. Execute fillOrder.
|
||||
/*
|
||||
EXCHANGE.executeTransaction(
|
||||
salt,
|
||||
signerAddress,
|
||||
signedExchangeTransaction,
|
||||
signature
|
||||
);
|
||||
);*/
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user