aboutsummaryrefslogtreecommitdiffstats
path: root/packages/fill-scenarios/src/fill_scenarios.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/fill-scenarios/src/fill_scenarios.ts')
-rw-r--r--packages/fill-scenarios/src/fill_scenarios.ts300
1 files changed, 300 insertions, 0 deletions
diff --git a/packages/fill-scenarios/src/fill_scenarios.ts b/packages/fill-scenarios/src/fill_scenarios.ts
new file mode 100644
index 000000000..8f2766e24
--- /dev/null
+++ b/packages/fill-scenarios/src/fill_scenarios.ts
@@ -0,0 +1,300 @@
+import { assetDataUtils, orderFactory } from '@0xproject/order-utils';
+import { AssetProxyId, ERC721AssetData, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { Provider } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { artifacts } from './artifacts';
+import { constants } from './constants';
+import { DummyERC20TokenContract } from './generated_contract_wrappers/dummy_erc20_token';
+import { DummyERC721TokenContract } from './generated_contract_wrappers/dummy_erc721_token';
+import { ExchangeContract } from './generated_contract_wrappers/exchange';
+
+export class FillScenarios {
+ private readonly _web3Wrapper: Web3Wrapper;
+ private readonly _userAddresses: string[];
+ private readonly _coinbase: string;
+ private readonly _zrxTokenAddress: string;
+ private readonly _exchangeAddress: string;
+ private readonly _erc20ProxyAddress: string;
+ private readonly _erc721ProxyAddress: string;
+ constructor(
+ provider: Provider,
+ userAddresses: string[],
+ zrxTokenAddress: string,
+ exchangeAddress: string,
+ erc20ProxyAddress: string,
+ erc721ProxyAddress: string,
+ ) {
+ this._web3Wrapper = new Web3Wrapper(provider);
+ this._userAddresses = userAddresses;
+ this._coinbase = userAddresses[0];
+ this._zrxTokenAddress = zrxTokenAddress;
+ this._exchangeAddress = exchangeAddress;
+ this._erc20ProxyAddress = erc20ProxyAddress;
+ this._erc721ProxyAddress = erc721ProxyAddress;
+ }
+ public async createFillableSignedOrderAsync(
+ makerAssetData: string,
+ takerAssetData: string,
+ makerAddress: string,
+ takerAddress: string,
+ fillableAmount: BigNumber,
+ expirationTimeSeconds?: BigNumber,
+ ): Promise<SignedOrder> {
+ return this.createAsymmetricFillableSignedOrderAsync(
+ makerAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ fillableAmount,
+ expirationTimeSeconds,
+ );
+ }
+ public async createFillableSignedOrderWithFeesAsync(
+ makerAssetData: string,
+ takerAssetData: string,
+ makerFee: BigNumber,
+ takerFee: BigNumber,
+ makerAddress: string,
+ takerAddress: string,
+ fillableAmount: BigNumber,
+ feeRecepientAddress: string,
+ expirationTimeSeconds?: BigNumber,
+ ): Promise<SignedOrder> {
+ return this._createAsymmetricFillableSignedOrderWithFeesAsync(
+ makerAssetData,
+ takerAssetData,
+ makerFee,
+ takerFee,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ fillableAmount,
+ feeRecepientAddress,
+ expirationTimeSeconds,
+ );
+ }
+ public async createAsymmetricFillableSignedOrderAsync(
+ makerAssetData: string,
+ takerAssetData: string,
+ makerAddress: string,
+ takerAddress: string,
+ makerFillableAmount: BigNumber,
+ takerFillableAmount: BigNumber,
+ expirationTimeSeconds?: BigNumber,
+ ): Promise<SignedOrder> {
+ const makerFee = new BigNumber(0);
+ const takerFee = new BigNumber(0);
+ const feeRecepientAddress = constants.NULL_ADDRESS;
+ return this._createAsymmetricFillableSignedOrderWithFeesAsync(
+ makerAssetData,
+ takerAssetData,
+ makerFee,
+ takerFee,
+ makerAddress,
+ takerAddress,
+ makerFillableAmount,
+ takerFillableAmount,
+ feeRecepientAddress,
+ expirationTimeSeconds,
+ );
+ }
+ public async createPartiallyFilledSignedOrderAsync(
+ makerAssetData: string,
+ takerAssetData: string,
+ takerAddress: string,
+ fillableAmount: BigNumber,
+ partialFillAmount: BigNumber,
+ ): Promise<SignedOrder> {
+ const [makerAddress] = this._userAddresses;
+ const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
+ makerAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ fillableAmount,
+ );
+ const exchangeInstance = new ExchangeContract(
+ artifacts.Exchange.compilerOutput.abi,
+ signedOrder.exchangeAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+
+ const orderWithoutExchangeAddress = _.omit(signedOrder, [
+ 'signature',
+ 'exchangeAddress',
+ ]) as OrderWithoutExchangeAddress;
+
+ const txHash = await exchangeInstance.fillOrder.sendTransactionAsync(
+ orderWithoutExchangeAddress,
+ partialFillAmount,
+ signedOrder.signature,
+ { from: takerAddress },
+ );
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ return signedOrder;
+ }
+ private async _createAsymmetricFillableSignedOrderWithFeesAsync(
+ makerAssetData: string,
+ takerAssetData: string,
+ makerFee: BigNumber,
+ takerFee: BigNumber,
+ makerAddress: string,
+ takerAddress: string,
+ makerFillableAmount: BigNumber,
+ takerFillableAmount: BigNumber,
+ feeRecepientAddress: string,
+ expirationTimeSeconds?: BigNumber,
+ ): Promise<SignedOrder> {
+ const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(makerAssetData);
+ if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
+ await this._increaseERC20BalanceAndAllowanceAsync(
+ decodedMakerAssetData.tokenAddress,
+ makerAddress,
+ makerFillableAmount,
+ );
+ } else {
+ if (!makerFillableAmount.equals(1)) {
+ throw new Error(`ERC721 makerFillableAmount should be equal 1. Found: ${makerFillableAmount}`);
+ }
+ await this._increaseERC721BalanceAndAllowanceAsync(
+ decodedMakerAssetData.tokenAddress,
+ makerAddress,
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ (decodedMakerAssetData as ERC721AssetData).tokenId,
+ );
+ }
+ const decodedTakerAssetData = assetDataUtils.decodeAssetDataOrThrow(takerAssetData);
+ if (decodedTakerAssetData.assetProxyId === AssetProxyId.ERC20) {
+ const takerTokenAddress = decodedTakerAssetData.tokenAddress;
+ await this._increaseERC20BalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount);
+ } else {
+ if (!takerFillableAmount.equals(1)) {
+ throw new Error(`ERC721 takerFillableAmount should be equal 1. Found: ${takerFillableAmount}`);
+ }
+ await this._increaseERC721BalanceAndAllowanceAsync(
+ decodedTakerAssetData.tokenAddress,
+ takerAddress,
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ (decodedMakerAssetData as ERC721AssetData).tokenId,
+ );
+ }
+ // Fees
+ await Promise.all([
+ this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
+ this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
+ ]);
+ const senderAddress = constants.NULL_ADDRESS;
+
+ const signedOrder = await orderFactory.createSignedOrderAsync(
+ this._web3Wrapper.getProvider(),
+ makerAddress,
+ takerAddress,
+ senderAddress,
+ makerFee,
+ takerFee,
+ makerFillableAmount,
+ makerAssetData,
+ takerFillableAmount,
+ takerAssetData,
+ this._exchangeAddress,
+ feeRecepientAddress,
+ expirationTimeSeconds,
+ );
+ return signedOrder;
+ }
+ private async _increaseERC721BalanceAndAllowanceAsync(
+ tokenAddress: string,
+ address: string,
+ tokenId: BigNumber,
+ ): Promise<void> {
+ await this._increaseERC721BalanceAsync(tokenAddress, address, tokenId);
+ await this._increaseERC721AllowanceAsync(tokenAddress, address, tokenId);
+ }
+ private async _increaseERC721AllowanceAsync(
+ tokenAddress: string,
+ address: string,
+ tokenId: BigNumber,
+ ): Promise<void> {
+ const erc721Token = new DummyERC721TokenContract(
+ artifacts.DummyERC721Token.compilerOutput.abi,
+ tokenAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ const txHash = await erc721Token.approve.sendTransactionAsync(this._erc721ProxyAddress, tokenId, {
+ from: address,
+ });
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ }
+ private async _increaseERC721BalanceAsync(
+ tokenAddress: string,
+ address: string,
+ tokenId: BigNumber,
+ ): Promise<void> {
+ const erc721Token = new DummyERC721TokenContract(
+ artifacts.DummyERC721Token.compilerOutput.abi,
+ tokenAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ try {
+ const currentOwner = await erc721Token.ownerOf.callAsync(tokenId);
+ if (currentOwner !== address) {
+ throw new Error(`Token ${tokenAddress}:${tokenId} is already owner by ${currentOwner}`);
+ }
+ } catch (err) {
+ const txHash = await erc721Token.mint.sendTransactionAsync(address, tokenId, { from: this._coinbase });
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ }
+ }
+ private async _increaseERC20BalanceAndAllowanceAsync(
+ tokenAddress: string,
+ address: string,
+ amount: BigNumber,
+ ): Promise<void> {
+ if (amount.isZero() || address === constants.NULL_ADDRESS) {
+ return; // noop
+ }
+ await Promise.all([
+ this._increaseERC20BalanceAsync(tokenAddress, address, amount),
+ this._increaseERC20AllowanceAsync(tokenAddress, address, amount),
+ ]);
+ }
+ private async _increaseERC20BalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
+ const erc20Token = new DummyERC20TokenContract(
+ artifacts.DummyERC20Token.compilerOutput.abi,
+ tokenAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ const txHash = await erc20Token.transfer.sendTransactionAsync(address, amount, {
+ from: this._coinbase,
+ });
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ }
+ private async _increaseERC20AllowanceAsync(
+ tokenAddress: string,
+ address: string,
+ amount: BigNumber,
+ ): Promise<void> {
+ const erc20Token = new DummyERC20TokenContract(
+ artifacts.DummyERC20Token.compilerOutput.abi,
+ tokenAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ const oldMakerAllowance = await erc20Token.allowance.callAsync(address, this._erc20ProxyAddress);
+ const newMakerAllowance = oldMakerAllowance.plus(amount);
+
+ const txHash = await erc20Token.approve.sendTransactionAsync(this._erc20ProxyAddress, newMakerAllowance, {
+ from: address,
+ });
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ }
+}