This repository has been archived by the owner on Oct 10, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 115
/
fill_erc20_limit_order.ts
149 lines (131 loc) · 6.19 KB
/
fill_erc20_limit_order.ts
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
import { ContractWrappers, ERC20TokenContract } from '@0x/contract-wrappers';
import { LimitOrder, OrderStatus, SignatureType } from '@0x/protocol-utils';
import { BigNumber, hexUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { NETWORK_CONFIGS, TX_DEFAULTS } from '../configs';
import { DECIMALS, NULL_ADDRESS, UNLIMITED_ALLOWANCE_IN_BASE_UNITS, ZERO } from '../constants';
import { PrintUtils } from '../print_utils';
import { providerEngine } from '../provider_engine';
import { calculateProtocolFee, getRandomFutureDateInSeconds, runMigrationsOnceIfRequiredAsync } from '../utils';
/**
* In this scenario, the maker creates and signs a limit order for selling
* ZRX for WETH.
*
* The taker takes this order and fills it via the 0x Exchange Proxy contract.
*/
export async function scenarioAsync(): Promise<void> {
await runMigrationsOnceIfRequiredAsync();
PrintUtils.printScenario('Fill ERC20 Limit Order');
// 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, { chainId: NETWORK_CONFIGS.chainId });
// Initialize the Web3Wrapper, this provides helper functions around fetching
// account information, balances, general contract logs
const web3Wrapper = new Web3Wrapper(providerEngine);
const [maker, taker] = await web3Wrapper.getAvailableAddressesAsync();
const exchangeProxyAddress = contractWrappers.contractAddresses.exchangeProxy;
const zrxTokenAddress = contractWrappers.contractAddresses.zrxToken;
const etherTokenAddress = contractWrappers.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);
// Allow the 0x Exchange Proxy to move ZRX on behalf of the maker
const zrxToken = new ERC20TokenContract(zrxTokenAddress, providerEngine);
const makerZRXApprovalTxHash = await zrxToken
.approve(contractWrappers.contractAddresses.exchangeProxy, UNLIMITED_ALLOWANCE_IN_BASE_UNITS)
.sendTransactionAsync({ from: maker, ...TX_DEFAULTS });
await printUtils.awaitTransactionMinedSpinnerAsync('Maker ZRX Approval', makerZRXApprovalTxHash);
// Allow the 0x Exchange Proxy to move WETH on behalf of the taker
const etherToken = contractWrappers.weth9;
const takerWETHApprovalTxHash = await etherToken
.approve(contractWrappers.contractAddresses.exchangeProxy, UNLIMITED_ALLOWANCE_IN_BASE_UNITS)
.sendTransactionAsync({ from: taker, ...TX_DEFAULTS });
await printUtils.awaitTransactionMinedSpinnerAsync('Taker WETH Approval', takerWETHApprovalTxHash);
// Convert ETH into WETH for taker by depositing ETH into the WETH contract
const takerWETHDepositTxHash = await etherToken.deposit().sendTransactionAsync({
from: taker,
value: takerAssetAmount,
...TX_DEFAULTS,
});
await printUtils.awaitTransactionMinedSpinnerAsync('Taker WETH Deposit', takerWETHDepositTxHash);
PrintUtils.printData('Setup', [
['Maker ZRX Approval', makerZRXApprovalTxHash],
['Taker WETH Approval', takerWETHApprovalTxHash],
['Taker WETH Deposit', takerWETHDepositTxHash],
]);
// Set up the Order and fill it
const randomExpiration = getRandomFutureDateInSeconds();
const pool = hexUtils.leftPad(1);
// Create the order
const limitOrder: LimitOrder = new LimitOrder({
chainId: NETWORK_CONFIGS.chainId,
verifyingContract: exchangeProxyAddress,
maker,
taker,
makerToken: zrxTokenAddress,
takerToken: etherTokenAddress,
makerAmount: makerAssetAmount,
takerAmount: takerAssetAmount,
takerTokenFeeAmount: ZERO,
sender: NULL_ADDRESS,
feeRecipient: NULL_ADDRESS,
expiry: randomExpiration,
pool,
salt: new BigNumber(Date.now()),
});
// Print order
printUtils.printOrder(limitOrder);
// Print out the Balances and Allowances
await printUtils.fetchAndPrintContractAllowancesAsync(contractWrappers.contractAddresses.exchangeProxy);
await printUtils.fetchAndPrintContractBalancesAsync();
// Generate the order hash and sign it
const signature = await limitOrder.getSignatureWithProviderAsync(
web3Wrapper.getProvider(),
SignatureType.EthSign,
maker,
);
const [{ orderHash, status }, remainingFillableAmount, isValidSignature] = await contractWrappers.exchangeProxy
.getLimitOrderRelevantState(limitOrder, signature)
.callAsync();
if (status === OrderStatus.Fillable && remainingFillableAmount.isGreaterThan(0) && isValidSignature) {
// Order is fillable
}
// get the protocol fee multiplier
// protocol fee = multiplier * gasPrice * numOrders
const protocolFeeMultiplier = new BigNumber(
await contractWrappers.exchangeProxy.getProtocolFeeMultiplier().callAsync(),
);
// Fill the Order via 0x Exchange Proxy contract
const txHash = await contractWrappers.exchangeProxy
.fillLimitOrder(limitOrder, signature, takerAssetAmount)
.sendTransactionAsync({
from: taker,
value: calculateProtocolFee(1, protocolFeeMultiplier),
...TX_DEFAULTS,
});
const txReceipt = await printUtils.awaitTransactionMinedSpinnerAsync('fillLimitOrder', txHash);
printUtils.printTransaction('fillLimitOrder', txReceipt, [['orderHash', orderHash]]);
// Print the Balances
await printUtils.fetchAndPrintContractBalancesAsync();
// Stop the Provider Engine
providerEngine.stop();
}
void (async () => {
try {
if (!module.parent) {
await scenarioAsync();
}
} catch (e) {
console.log(e);
providerEngine.stop();
process.exit(1);
}
})();