forked from 0xProject/0x-starter-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fill_erc20_otc_order.ts
139 lines (121 loc) · 5.7 KB
/
fill_erc20_otc_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
import { ContractWrappers, ERC20TokenContract } from '@0x/contract-wrappers';
import { OrderStatus, OtcOrder, SignatureType } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { NETWORK_CONFIGS, TX_DEFAULTS } from '../configs';
import { DECIMALS, UNLIMITED_ALLOWANCE_IN_BASE_UNITS } from '../constants';
import { PrintUtils } from '../print_utils';
import { providerEngine } from '../provider_engine';
import { getRandomFutureDateInSeconds, runMigrationsOnceIfRequiredAsync } from '../utils';
/**
* In this scenario, the maker creates and signs an OTC 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 OTC 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 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 erc20Token = new ERC20TokenContract(zrxTokenAddress, providerEngine);
const makerZRXApprovalTxHash = await erc20Token
.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 nonceBucket = new BigNumber(0);
const nonce = (await contractWrappers.exchangeProxy
.lastOtcTxOriginNonce(taker, nonceBucket)
.callAsync()).plus(1);
const expiryAndNonce = OtcOrder.encodeExpiryAndNonce(randomExpiration, nonceBucket, nonce);
// Create the order
const otcOrder: OtcOrder = new OtcOrder({
chainId: NETWORK_CONFIGS.chainId,
verifyingContract: contractWrappers.contractAddresses.exchangeProxy,
maker,
taker,
makerToken: zrxTokenAddress,
takerToken: etherTokenAddress,
makerAmount: makerAssetAmount,
takerAmount: takerAssetAmount,
txOrigin: taker,
expiryAndNonce,
});
// Print order
printUtils.printOrder(otcOrder);
// 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 otcOrder.getSignatureWithProviderAsync(web3Wrapper.getProvider(), SignatureType.EthSign, maker);
const {
orderHash,
status,
} = await contractWrappers.exchangeProxy.getOtcOrderInfo(otcOrder).callAsync();
if (status === OrderStatus.Fillable) {
// Order is fillable
}
// Fill the Order via 0x Exchange Proxy contract
const txHash = await contractWrappers.exchangeProxy
.fillOtcOrder(otcOrder, signature, takerAssetAmount)
.sendTransactionAsync({
from: taker,
...TX_DEFAULTS,
});
const txReceipt = await printUtils.awaitTransactionMinedSpinnerAsync('fillOtcOrder', txHash);
printUtils.printTransaction('fillOtcOrder', 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);
}
})();