Created
January 6, 2020 20:13
-
-
Save coopermaruyama/10605bc36da6886f4fa10bf1dcd2fc63 to your computer and use it in GitHub Desktop.
Create a signed order using 0x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Generate a signed ZRX order | |
// | |
// Requires ts-node and tsconfig-paths to be installed | |
// | |
// USAGE EXAMPLE (Sell 5 orchid for 1 ETH): | |
// | |
// ERC20_ADDRESS=0x4575f41308EC1483f3d399aa9a2826d74Da13Deb \ | |
// SELL_AMOUNT=5 \ | |
// SELL_FOR_ETH_AMOUNT=1 \ | |
// PRIV=123A.....875348 \ | |
// ts-node -O '{"target": "es2017", "module": "commonjs"}' -r tsconfig-paths/register generate-signed-order.ts | |
// | |
import { ContractWrappers, ERC20TokenContract } from '@0x/contract-wrappers'; | |
import { generatePseudoRandomSalt, Order, signatureUtils, orderHashUtils, assetDataUtils, SignedOrder } from '@0x/order-utils'; | |
import Web3 from 'web3'; | |
import { PrivateKeyWalletSubprovider, RPCSubprovider, Web3ProviderEngine, SupportedProvider } from '@0x/subproviders'; | |
import erc20ABI from 'human-standard-token-abi'; | |
import { BigNumber } from '@0x/utils'; | |
import ethUtil from 'ethereumjs-util'; | |
import Bluebird from 'bluebird'; | |
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; | |
// Ensure env vars are passed | |
if (!process.env.ERC20_ADDRESS) { | |
throw 'ERC20_ADDRESS is a required env var'; | |
} | |
if (!process.env.SELL_AMOUNT) { | |
throw `SELL_AMOUNT is a required env var`; | |
} | |
if (!process.env.SELL_FOR_ETH_AMOUNT) { | |
throw `SELL_FOR_ETH_AMOUNT is a required env var`; | |
} | |
if (!process.env.PRIV) { | |
throw `PRIV is a required env var`; | |
} | |
const EXCHANGE_ADDRESS = '0x61935cbdd02287b511119ddb11aeb42f1593b7ef'; | |
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; | |
const FEE_RECIPIENT = '0x529bd031bb5ed1a3c1a40b016c5787f279cf8ada'; | |
const WETH_ASSET_DATA = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; | |
const NULL_BYTES = '0x'; | |
const FEE = new BigNumber('0.05'); | |
const MS_IN_ONE_SECOND = 1000; | |
const CHAIN_ID = 1; // mainnet | |
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); | |
async function createOrder( | |
tokenAddress: string, | |
sellAmount: BigNumber, | |
sellForEthAmount: BigNumber, | |
priv: string | |
): Promise<SignedOrder> { | |
const providerEngine = new Web3ProviderEngine(); | |
const privSubprovider = new PrivateKeyWalletSubprovider(priv); | |
providerEngine.addProvider(privSubprovider); | |
providerEngine.addProvider(new RPCSubprovider(`https://mainnet.infura.io`)); | |
providerEngine.start(); | |
const now = new BigNumber(Date.now() / MS_IN_ONE_SECOND).integerValue(); | |
const privBuff = Buffer.from(priv, 'hex'); | |
const pubBuff = ethUtil.privateToAddress(privBuff); | |
const pub = `0x${pubBuff.toString('hex')}`; | |
const makerAssetData = assetDataUtils.encodeERC20AssetData( | |
tokenAddress | |
); | |
const provider = new Web3.providers.HttpProvider(`https://mainnet.infura.io`); | |
const web3 = new Web3(provider); | |
const Token = web3.eth.contract(erc20ABI); | |
const makerToken = Token.at(tokenAddress); | |
const makerDecimals = await Bluebird.promisify<string>(makerToken.decimals)(); | |
const expMaker = new BigNumber(10).pow(+makerDecimals); | |
const expEth = new BigNumber(10).pow(18); | |
// approve the exchange to spend tokens on our behalf | |
await approve(pub, tokenAddress, provider); | |
// Create the order | |
const order: Order = { | |
exchangeAddress: EXCHANGE_ADDRESS, | |
makerAddress: pub, | |
takerAddress: NULL_ADDRESS, | |
senderAddress: NULL_ADDRESS, | |
feeRecipientAddress: pub, | |
expirationTimeSeconds: now.plus(900), // 15 Minutes | |
salt: generatePseudoRandomSalt(), | |
makerAssetAmount: sellAmount.times(expMaker), | |
takerAssetAmount: sellForEthAmount.times(expEth), | |
makerAssetData, | |
takerAssetData: WETH_ASSET_DATA, | |
makerFee: new BigNumber(0), | |
// takerFee: sellForEthAmount.times(FEE), | |
takerFee: new BigNumber(0), | |
makerFeeAssetData: '0x', | |
takerFeeAssetData: '0x', | |
chainId: 1 | |
}; | |
const signedOrder = await signatureUtils.ecSignOrderAsync(providerEngine, order, pub); | |
providerEngine.stop(); | |
return signedOrder; | |
} | |
async function approve(walletAddr: string, tokenAddr: string, provider: SupportedProvider) { | |
const contractAddrs = getContractAddressesForChainOrThrow(CHAIN_ID); | |
const erc20 = new ERC20TokenContract(tokenAddr, provider); | |
const allowance = await erc20.allowance( | |
walletAddr, | |
contractAddrs.erc20Proxy | |
).callAsync(); | |
// Create allowance tx. | |
if (allowance.eq(0)) { | |
await erc20.approve( | |
contractAddrs.erc20Proxy, | |
MAX_UINT256 | |
).sendTransactionAsync({ from: walletAddr }); | |
} | |
} | |
createOrder( | |
process.env.ERC20_ADDRESS, | |
new BigNumber(process.env.SELL_AMOUNT), | |
new BigNumber(process.env.SELL_FOR_ETH_AMOUNT), | |
process.env.PRIV | |
).then(console.log); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment