0x-start-project源码学习 - 6

之前说过因为ETH不是ERC20标准,所以无法直接使用ETH进行交易,但是可以通过将ETH兑换为WETH来进行交易,不过这样麻烦的是每次交易需要兑换WETH,并进行授权才可以进行交易。
0x还提供了另一种方法,那就是使用forwarder,forwarder的翻译是

1
2
3
forwarder
英 ['fɔːwədə] 美 ['fɔrwɚdɚ]
n. 运送者,促进者;传送装置

我理解的是更多是促进者的意思,就是帮助用户促成交易的工具,主要是实现快速通过ETH进行交易,自动完成ETHWETH兑换的过程,对用户而言相当于直接使用ETH完成了交易。

forwarder就是专门实现ETH自动兑换执行交易的的库,它只有两个方法:

1
2
3
4
5
6
7
8
// Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value
// 这个还是不很清楚
marketSellOrdersWithEthAsync
// Attempt to purchase makerAssetFillAmount of makerAsset by selling ethAmount provided with transaction.
// 直接支付ETH购买相应ERC20资产
marketBuyOrdersWithEthAsync

maker对订单签名后直接可以使用ETH参与订单交易:

1
2
3
4
5
6
7
8
9
10
11
12
txHash = await contractWrappers.forwarder.marketBuyOrdersWithEthAsync(
[signedOrder],
order.makerAssetAmount,
taker,
order.takerAssetAmount,
[],
0,
NULL_ADDRESS,
{
gasLimit: TX_DEFAULTS.gas,
},
);

ERC721则类似,只需要将signedOrder信息换为对应ERC721信息即可。

forwarder_bug_erc20_tokens对应代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
PrintUtils.printScenario('Forwarder Buy Tokens');
// Initialize the ContractWrappers, this provides helper functions around calling
// 0x contracts as well as ERC20/ERC721 token contracts on the blockchain
const contractWrappers = new ContractWrappers(providerEngine, { networkId: NETWORK_CONFIGS.networkId });
// Initialize the Web3Wrapper, this provides helper functions around fetching
// account information, balances, general contract logs
// 获取maker,taker地址
const web3Wrapper = new Web3Wrapper(providerEngine);
const [maker, taker] = await web3Wrapper.getAvailableAddressesAsync();
const zrxTokenAddress = contractAddresses.zrxToken;
const etherTokenAddress = contractAddresses.etherToken;
const printUtils = new PrintUtils(
web3Wrapper,
contractWrappers,
{ maker, taker },
{ WETH: etherTokenAddress, ZRX: zrxTokenAddress },
);
printUtils.printAccounts();
// 设置交易金额
// the amount the maker is selling of maker asset
const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), DECIMALS);
// the amount the maker wants of taker asset
const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.1), DECIMALS);
// 0x v2 uses hex encoded asset data strings to encode all the information needed to identify an asset
// 设置交易资产信息
const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenAddress);
const takerAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress);
let txHash;
let txReceipt;
// 进行对应资产授权
// Allow the 0x ERC20 Proxy to move ZRX on behalf of makerAccount
const makerZRXApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(
zrxTokenAddress,
maker,
);
await printUtils.awaitTransactionMinedSpinnerAsync('Maker ZRX Approval', makerZRXApprovalTxHash);
// With the Forwarding contract, the taker requires no set up
PrintUtils.printData('Setup', [['Maker ZRX Approval', makerZRXApprovalTxHash]]);
// Set up the Order and fill it
const randomExpiration = getRandomFutureDateInSeconds();
const exchangeAddress = contractAddresses.exchange;
// Create the order
// 创建订单
const order: Order = {
exchangeAddress,
makerAddress: maker,
takerAddress: NULL_ADDRESS,
senderAddress: NULL_ADDRESS,
feeRecipientAddress: NULL_ADDRESS,
expirationTimeSeconds: randomExpiration,
salt: generatePseudoRandomSalt(),
makerAssetAmount,
takerAssetAmount,
makerAssetData,
takerAssetData,
makerFee: ZERO,
takerFee: ZERO,
};
printUtils.printOrder(order);
// Print out the Balances and Allowances
await printUtils.fetchAndPrintContractAllowancesAsync();
await printUtils.fetchAndPrintContractBalancesAsync();
// Generate the order hash and sign it
// 对订单进行签名
const orderHashHex = orderHashUtils.getOrderHashHex(order);
const signature = await signatureUtils.ecSignHashAsync(providerEngine, orderHashHex, maker);
const signedOrder = {
...order,
signature,
};
// Use the Forwarder to market buy the ERC20 orders using Eth. When using the Forwarder
// the taker does not need to set any allowances or deposit any ETH into WETH
// 使用Forwarder直接通过ETH交换对应代币,不需要兑换为WETH
txHash = await contractWrappers.forwarder.marketBuyOrdersWithEthAsync(
[signedOrder],
order.makerAssetAmount,
taker,
order.takerAssetAmount,
[],
0,
NULL_ADDRESS,
{
gasLimit: TX_DEFAULTS.gas,
},
);
txReceipt = await printUtils.awaitTransactionMinedSpinnerAsync('marketBuyTokensWithEth', txHash);
printUtils.printTransaction('marketBuyTokensWithEth', txReceipt, [['orderHash', orderHashHex]]);
// Print the Balances
await printUtils.fetchAndPrintContractBalancesAsync();
// Stop the Provider Engine
providerEngine.stop();