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

在之前说过的如:

1
2
3
fillOrderERC20
fillOrderFees
fillOrderERC721

的例子中,都是由taker进行最后的交易确认,所以taker都是最后的交易执行者,他负责支付执行合约需要的费用(ETH)。

executeTransaction的例子中还有一个类似委托的模式来执行交易,就是maker来生成订单,然后进行签名。taker同样对这个订单进行签名,然后交给sender进行执行。sender是最后交易的执行者,支付执行合约的费用。

这个模式下,maker只需要提供对应的订单信息,由taker签名后交给sender即可。

当然maker如果在真正的执行交易前不想进行交易,可以通过transactionEncoder.cancelOrderTx来取消这个订单。这是该订单即无法进行交易。

transactionEncoder主要的功能应该就是引入第三方来促成交易。

相关源码:

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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
PrintUtils.printScenario('Execute Transaction fillOrder');
// 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
const web3Wrapper = new Web3Wrapper(providerEngine);
// 获取maker,taker,sender地址
const [maker, taker, sender] = await web3Wrapper.getAvailableAddressesAsync();
const feeRecipientAddress = sender;
const zrxTokenAddress = contractAddresses.zrxToken;
const etherTokenAddress = contractAddresses.etherToken;
const printUtils = new PrintUtils(
web3Wrapper,
contractWrappers,
{ maker, taker, sender },
{ 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);
// the amount of fees the maker pays in ZRX
const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.01), DECIMALS);
// the amount of fees the taker pays in ZRX
const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.01), 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;
// 对代币账户进行授权
// Approve the ERC20 Proxy to move ZRX for maker
const makerZRXApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(
zrxTokenAddress,
maker,
);
await printUtils.awaitTransactionMinedSpinnerAsync('Maker ZRX Approval', makerZRXApprovalTxHash);
// Approve the ERC20 Proxy to move ZRX for taker
const takerZRXApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(
zrxTokenAddress,
taker,
);
await printUtils.awaitTransactionMinedSpinnerAsync('Taker ZRX Approval', takerZRXApprovalTxHash);
// Approve the ERC20 Proxy to move WETH for taker
const takerWETHApprovalTxHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(
etherTokenAddress,
taker,
);
await printUtils.awaitTransactionMinedSpinnerAsync('Taker WETH Approval', takerWETHApprovalTxHash);
// Convert ETH into WETH for taker by depositing ETH into the WETH contract
const takerWETHDepositTxHash = await contractWrappers.etherToken.depositAsync(
etherTokenAddress,
takerAssetAmount,
taker,
);
await printUtils.awaitTransactionMinedSpinnerAsync('Taker WETH Deposit', takerWETHDepositTxHash);
PrintUtils.printData('Setup', [
['Maker ZRX Approval', makerZRXApprovalTxHash],
['Taker ZRX Approval', takerZRXApprovalTxHash],
['Taker WETH Approval', takerWETHApprovalTxHash],
['Taker WETH Deposit', takerWETHDepositTxHash],
]);
// Set up the Order and fill it
// 获取过期时间
const randomExpiration = getRandomFutureDateInSeconds();
// 生成未签名订单
// Create the order
const orderWithoutExchangeAddress = {
makerAddress: maker,
takerAddress: NULL_ADDRESS,
senderAddress: NULL_ADDRESS,
feeRecipientAddress,
expirationTimeSeconds: randomExpiration,
salt: generatePseudoRandomSalt(),
makerAssetAmount,
takerAssetAmount,
makerAssetData,
takerAssetData,
makerFee,
takerFee,
};
// 设置交易地址-0x地址
const exchangeAddress = contractAddresses.exchange;
const order: Order = {
...orderWithoutExchangeAddress,
exchangeAddress,
};
printUtils.printOrder(order);
// Print out the Balances and Allowances
await printUtils.fetchAndPrintContractAllowancesAsync();
await printUtils.fetchAndPrintContractBalancesAsync();
// maer对订单进行签名
// Generate the order hash and sign it
const orderHashHex = orderHashUtils.getOrderHashHex(order);
const signature = await signatureUtils.ecSignHashAsync(providerEngine, orderHashHex, maker);
const signedOrder: SignedOrder = {
...order,
signature,
};
// 执行交易
// The transaction encoder provides helpers in encoding 0x Exchange transactions to allow
// a third party to submit the transaction. This operates in the context of the signer (taker)
// rather then the context of the submitter (sender)
// transactionEncoder包装交易信息
const transactionEncoder = await contractWrappers.exchange.transactionEncoderAsync();
// This is an ABI encoded function call that the taker wishes to perform
// in this scenario it is a fillOrder
// 如果希望取消交易那么使用cancelOrderTx即可
// const cancelData = transactionEncoder.cancelOrderTx(signedOrder);
const fillData = transactionEncoder.fillOrderTx(signedOrder, takerAssetAmount);
// Generate a random salt to mitigate replay attacks
const takerTransactionSalt = generatePseudoRandomSalt();
// The taker signs the operation data (fillOrder) with the salt
// taker对交易进行签名
// 如果是要取消交易的话,签名应该由maker进行签名
const executeTransactionHex = transactionEncoder.getTransactionHashHex(fillData, takerTransactionSalt, taker);
const takerSignatureHex = await signatureUtils.ecSignHashAsync(providerEngine, executeTransactionHex, taker);
// The sender submits this operation via executeTransaction passing in the signature from the taker
// sender使用taker提供的签名执行交易
txHash = await contractWrappers.exchange.executeTransactionAsync(
takerTransactionSalt,
taker,
fillData,
takerSignatureHex,
sender,
{
gasLimit: TX_DEFAULTS.gas,
},
);
const txReceipt = await printUtils.awaitTransactionMinedSpinnerAsync('executeTransaction', txHash);
printUtils.printTransaction('Execute Transaction fillOrder', txReceipt, [['orderHash', orderHashHex]]);
// Print the Balances
await printUtils.fetchAndPrintContractBalancesAsync();
// Stop the Provider Engine
providerEngine.stop();