MetaTransaction V2 Utility Packages (#714)

* add utility class for MetaTransactionsV2, update artifacts, update wrappers

* fix exports

* update artifacts, update wrappers

* update changelogs
This commit is contained in:
Andy 2023-04-24 06:03:23 -04:00 committed by GitHub
parent e57fc60a76
commit a7acf2951d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1808 additions and 233 deletions

View File

@ -1,4 +1,12 @@
[ [
{
"version": "3.19.0",
"changes": [
{
"note": "Regenerate IZeroEx artifact"
}
]
},
{ {
"timestamp": 1674517560, "timestamp": 1674517560,
"version": "3.18.3", "version": "3.18.3",

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,12 @@
[ [
{
"version": "13.23.0",
"changes": [
{
"note": "Regenerate IZeroEx wrapper"
}
]
},
{ {
"timestamp": 1681969282, "timestamp": 1681969282,
"version": "13.22.21", "version": "13.22.21",

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,12 @@
[ [
{
"version": "11.22.0",
"changes": [
{
"note": "Add MetaTransactionV2 utilities"
}
]
},
{ {
"version": "11.21.0", "version": "11.21.0",
"changes": [ "changes": [

View File

@ -12,6 +12,7 @@ export const NFTOrder = {
export * from './eip712_utils'; export * from './eip712_utils';
export * from './orders'; export * from './orders';
export * from './meta_transactions'; export * from './meta_transactions';
export * from './meta_transactions_v2';
export * from './signature_utils'; export * from './signature_utils';
export * from './transformer_utils'; export * from './transformer_utils';
export * from './constants'; export * from './constants';

View File

@ -0,0 +1,143 @@
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { EIP712TypedData } from '@0x/types';
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
import { ZERO } from './constants';
import {
createExchangeProxyEIP712Domain,
EIP712_DOMAIN_PARAMETERS,
getExchangeProxyEIP712Hash,
getTypeHash,
} from './eip712_utils';
export interface MetaTransactionV2Fee {
recipient: string,
amount: BigNumber,
}
const MTX_DEFAULT_VALUES = {
signer: NULL_ADDRESS,
sender: NULL_ADDRESS,
expirationTimeSeconds: ZERO,
salt: ZERO,
callData: hexUtils.leftPad(0),
feeToken: NULL_ADDRESS,
fees: [] as MetaTransactionV2Fee[],
chainId: 1,
verifyingContract: getContractAddressesForChainOrThrow(1).exchangeProxy,
};
export type MetaTransactionV2Fields = typeof MTX_DEFAULT_VALUES;
export class MetaTransactionV2 {
public static readonly FEE_STRUCT_NAME = 'MetaTransactionFeeData';
public static readonly FEE_STRUCT_ABI = [
{ type: 'address', name: 'recipient' },
{ type: 'uint256', name: 'amount' },
];
public static readonly FEE_TYPE_HASH = getTypeHash(MetaTransactionV2.FEE_STRUCT_NAME, MetaTransactionV2.FEE_STRUCT_ABI);
public static readonly MTX_STRUCT_NAME = 'MetaTransactionDataV2';
public static readonly MTX_STRUCT_ABI = [
{ type: 'address', name: 'signer' },
{ type: 'address', name: 'sender' },
{ type: 'uint256', name: 'expirationTimeSeconds' },
{ type: 'uint256', name: 'salt' },
{ type: 'bytes', name: 'callData' },
{ type: 'address', name: 'feeToken' },
{ type: `${MetaTransactionV2.FEE_STRUCT_NAME}[]`, name: 'fees' },
];
public static readonly MTX_TYPE_HASH = getTypeHash(
MetaTransactionV2.MTX_STRUCT_NAME,
MetaTransactionV2.MTX_STRUCT_ABI,
{ [MetaTransactionV2.FEE_STRUCT_NAME]: MetaTransactionV2.FEE_STRUCT_ABI }
);
public signer: string;
public sender: string;
public expirationTimeSeconds: BigNumber;
public salt: BigNumber;
public callData: string;
public feeToken: string;
public fees: MetaTransactionV2Fee[];
public chainId: number;
public verifyingContract: string;
public constructor(fields: Partial<MetaTransactionV2Fields> = {}) {
const _fields = { ...MTX_DEFAULT_VALUES, ...fields };
this.signer = _fields.signer;
this.sender = _fields.sender;
this.expirationTimeSeconds = _fields.expirationTimeSeconds;
this.salt = _fields.salt;
this.callData = _fields.callData;
this.feeToken = _fields.feeToken;
this.fees = _fields.fees;
this.chainId = _fields.chainId;
this.verifyingContract = _fields.verifyingContract;
}
public clone(fields: Partial<MetaTransactionV2Fields> = {}): MetaTransactionV2 {
return new MetaTransactionV2({
signer: this.signer,
sender: this.sender,
expirationTimeSeconds: this.expirationTimeSeconds,
salt: this.salt,
callData: this.callData,
feeToken: this.feeToken,
fees: this.fees,
chainId: this.chainId,
verifyingContract: this.verifyingContract,
...fields,
});
}
public getStructHash(): string {
const feesHash = hexUtils.hash(hexUtils.concat(
...this.fees.map((fee) => hexUtils.hash(hexUtils.concat(
hexUtils.leftPad(MetaTransactionV2.FEE_TYPE_HASH),
hexUtils.leftPad(fee.recipient),
hexUtils.leftPad(fee.amount),
)))
));
return hexUtils.hash(
hexUtils.concat(
hexUtils.leftPad(MetaTransactionV2.MTX_TYPE_HASH),
hexUtils.leftPad(this.signer),
hexUtils.leftPad(this.sender),
hexUtils.leftPad(this.expirationTimeSeconds),
hexUtils.leftPad(this.salt),
hexUtils.hash(this.callData),
hexUtils.leftPad(this.feeToken),
hexUtils.leftPad(feesHash),
),
);
}
public getEIP712TypedData(): EIP712TypedData {
return {
types: {
EIP712Domain: EIP712_DOMAIN_PARAMETERS,
[MetaTransactionV2.MTX_STRUCT_NAME]: MetaTransactionV2.MTX_STRUCT_ABI,
[MetaTransactionV2.FEE_STRUCT_NAME]: MetaTransactionV2.FEE_STRUCT_ABI,
},
domain: createExchangeProxyEIP712Domain(this.chainId, this.verifyingContract) as any,
primaryType: MetaTransactionV2.MTX_STRUCT_NAME,
message: {
signer: this.signer,
sender: this.sender,
expirationTimeSeconds: this.expirationTimeSeconds.toString(10),
salt: this.salt.toString(10),
callData: this.callData,
feeToken: this.feeToken,
fees: this.fees.map(({recipient, amount}) => ({
recipient,
amount: amount.toString(10),
})) as any,
},
};
}
public getHash(): string {
return getExchangeProxyEIP712Hash(this.getStructHash(), this.chainId, this.verifyingContract);
}
}

View File

@ -0,0 +1,66 @@
import { chaiSetup, } from '@0x/dev-utils';
import { BigNumber } from '@0x/utils';
import { expect } from 'chai';
import { MetaTransactionV2 } from '../src/meta_transactions_v2';
chaiSetup.configure();
describe('mtxs v2', () => {
describe('MetaTransactionV2 (no fees)', () => {
const mtx = new MetaTransactionV2({
signer: '0x349e8d89e8b37214d9ce3949fc5754152c525bc3',
sender: '0x83c62b2e67dea0df2a27be0def7a22bd7102642c',
expirationTimeSeconds: new BigNumber(9101112),
salt: new BigNumber(2001),
callData: '0x12345678',
feeToken: '0xcc3c7ea403427154ec908203ba6c418bd699f7ce',
fees: [] as any,
chainId: 8008,
verifyingContract: '0x6701704d2421c64ee9aa93ec7f96ede81c4be77d',
});
it('can get the struct hash', () => {
const actual = mtx.getStructHash();
const expected = '0x57db4055edfed82a6d86103197c21390bf29412fb4585e08c708454e03d92516';
expect(actual).to.eq(expected);
});
it('can get the EIP712 hash', () => {
const actual = mtx.getHash();
const expected = '0x05fc975cb9f37cc442a2975bc479502ce33d2d068fe8a1d6f50dbb11c1499137';
expect(actual).to.eq(expected);
});
});
describe('MetaTransactionV2 (two fees)', () => {
const mtx = new MetaTransactionV2({
signer: '0x349e8d89e8b37214d9ce3949fc5754152c525bc3',
sender: '0x83c62b2e67dea0df2a27be0def7a22bd7102642c',
expirationTimeSeconds: new BigNumber(9101112),
salt: new BigNumber(2001),
callData: '0x12345678',
feeToken: '0xcc3c7ea403427154ec908203ba6c418bd699f7ce',
fees: [{
recipient: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
amount: new BigNumber(1000000),
}, {
recipient: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
amount: new BigNumber(1000),
}] as any,
chainId: 8008,
verifyingContract: '0x6701704d2421c64ee9aa93ec7f96ede81c4be77d',
});
it('can get the struct hash', () => {
const actual = mtx.getStructHash();
const expected = '0x441c8b8a8f25c1716f2880326d008d07d0b8eb9606623c0a81dd5d9fa14dd12e';
expect(actual).to.eq(expected);
});
it('can get the EIP712 hash', () => {
const actual = mtx.getHash();
const expected = '0xfc85ef2149bd49fcc8fee2571ed8f0ecd671dec03845637ab1ded3d891ac3386';
expect(actual).to.eq(expected);
});
});
});