aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-07-19 07:21:24 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-07-31 04:58:19 +0800
commita7238d0fdb302d7062f3f63c3119910286f992c5 (patch)
tree6fbfb256537f0727dcb4dfe9fcce24434b537e26 /packages
parent02eb575813564b0586a038cc1229a166cb402146 (diff)
downloaddexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.tar
dexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.tar.gz
dexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.tar.bz2
dexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.tar.lz
dexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.tar.xz
dexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.tar.zst
dexon-0x-contracts-a7238d0fdb302d7062f3f63c3119910286f992c5.zip
Implement initial forwarder wrapper
Diffstat (limited to 'packages')
-rw-r--r--packages/contract-wrappers/package.json4
-rw-r--r--packages/contract-wrappers/src/artifacts.ts2
-rw-r--r--packages/contract-wrappers/src/contract_wrappers.ts7
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts170
-rw-r--r--packages/contract-wrappers/src/index.ts1
-rw-r--r--packages/contract-wrappers/src/types.ts2
-rw-r--r--packages/contract-wrappers/src/utils/constants.ts1
-rw-r--r--packages/contract-wrappers/test/forwarder_wrapper_test.ts57
8 files changed, 242 insertions, 2 deletions
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index ed0278caa..f27afaba9 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -14,7 +14,7 @@
"watch_without_deps": "yarn pre_build && tsc -w",
"build": "yarn pre_build && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
"pre_build": "run-s update_artifacts_v2_beta update_artifacts_v2 generate_contract_wrappers copy_artifacts",
- "generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
+ "generate_contract_wrappers": "abi-gen --abis 'src/artifacts/@(Exchange|DummyERC20Token|DummyERC721Token|ZRXToken|ERC20Token|ERC721Token|WETH9|ERC20Proxy|ERC721Proxy|Forwarder).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers",
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
"test:circleci": "run-s test:coverage",
"test": "yarn run_mocha",
@@ -29,7 +29,7 @@
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
},
"config": {
- "contracts_v2_beta": "Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken",
+ "contracts_v2_beta": "Exchange ERC20Proxy ERC20Token ERC721Proxy ERC721Token WETH9 ZRXToken Forwarder",
"contracts_v2": "DummyERC20Token DummyERC721Token"
},
"repository": {
diff --git a/packages/contract-wrappers/src/artifacts.ts b/packages/contract-wrappers/src/artifacts.ts
index 742d0e1b2..2481b311a 100644
--- a/packages/contract-wrappers/src/artifacts.ts
+++ b/packages/contract-wrappers/src/artifacts.ts
@@ -7,6 +7,7 @@ import * as ERC20Token from './artifacts/ERC20Token.json';
import * as ERC721Proxy from './artifacts/ERC721Proxy.json';
import * as ERC721Token from './artifacts/ERC721Token.json';
import * as Exchange from './artifacts/Exchange.json';
+import * as Forwarder from './artifacts/Forwarder.json';
import * as EtherToken from './artifacts/WETH9.json';
import * as ZRXToken from './artifacts/ZRXToken.json';
@@ -20,4 +21,5 @@ export const artifacts = {
EtherToken: (EtherToken as any) as ContractArtifact,
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
+ Forwarder: (Forwarder as any) as ContractArtifact,
};
diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts
index 8010242c5..76aefbdcf 100644
--- a/packages/contract-wrappers/src/contract_wrappers.ts
+++ b/packages/contract-wrappers/src/contract_wrappers.ts
@@ -11,6 +11,7 @@ import { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
import { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper';
import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
+import { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
import { ContractWrappersConfigSchema } from './schemas/contract_wrappers_config_schema';
import { contractWrappersPrivateNetworkConfigSchema } from './schemas/contract_wrappers_private_network_config_schema';
import { contractWrappersPublicNetworkConfigSchema } from './schemas/contract_wrappers_public_network_config_schema';
@@ -47,6 +48,11 @@ export class ContractWrappers {
* erc721Proxy smart contract.
*/
public erc721Proxy: ERC721ProxyWrapper;
+ /**
+ * An instance of the ForwarderWrapper class containing methods for interacting with any Forwarder smart contract.
+ */
+ public forwarder: ForwarderWrapper;
+
private _web3Wrapper: Web3Wrapper;
/**
* Instantiates a new ContractWrappers instance.
@@ -104,6 +110,7 @@ export class ContractWrappers {
config.zrxContractAddress,
blockPollingIntervalMs,
);
+ this.forwarder = new ForwarderWrapper(this._web3Wrapper, config.networkId, config.forwarderContractAddress);
}
/**
* Sets a new web3 provider for 0x.js. Updating the provider will stop all
diff --git a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
new file mode 100644
index 000000000..56533fb78
--- /dev/null
+++ b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts
@@ -0,0 +1,170 @@
+import { schemas } from '@0xproject/json-schemas';
+import { AssetProxyId, SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import { ContractAbi } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { artifacts } from '../artifacts';
+import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
+import { txOptsSchema } from '../schemas/tx_opts_schema';
+import { TransactionOpts } from '../types';
+import { assert } from '../utils/assert';
+import { constants } from '../utils/constants';
+
+import { ContractWrapper } from './contract_wrapper';
+import { ForwarderContract } from './generated/forwarder';
+
+/**
+ * This class includes the functionality related to interacting with the Forwarder contract.
+ */
+export class ForwarderWrapper extends ContractWrapper {
+ public abi: ContractAbi = artifacts.Forwarder.compilerOutput.abi;
+ private _forwarderContractIfExists?: ForwarderContract;
+ private _contractAddressIfExists?: string;
+ constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
+ super(web3Wrapper, networkId);
+ this._contractAddressIfExists = contractAddressIfExists;
+ }
+ /**
+ * Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
+ * Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
+ * 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
+ * Any ETH not spent will be refunded to sender.
+ * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
+ * All orders must specify WETH as the takerAsset
+ * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
+ * Provider provided at instantiation.
+ * @param ethAmount The amount of eth to send with the transaction
+ * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
+ * Used to purchase ZRX for primary order fees.
+ * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
+ * Defaults to 0.
+ * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
+ * @param txOpts Transaction parameters.
+ * @return Transaction hash.
+ */
+ public async marketSellOrdersWithEthAsync(
+ signedOrders: SignedOrder[],
+ takerAddress: string,
+ ethAmount: BigNumber,
+ signedFeeOrders: SignedOrder[] = [],
+ feePercentage: BigNumber = constants.ZERO_AMOUNT,
+ feeRecipientAddress: string = constants.NULL_ADDRESS,
+ txOpts: TransactionOpts = {},
+ ): Promise<string> {
+ assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
+ await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
+ assert.isBigNumber('ethAmount', ethAmount);
+ assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
+ assert.isBigNumber('feePercentage', feePercentage);
+ assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
+ assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
+ const normalizedTakerAddress = takerAddress.toLowerCase();
+ const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
+ const ForwarderContractInstance = await this._getForwarderContractAsync();
+ const txHash = await ForwarderContractInstance.marketSellOrdersWithEth.sendTransactionAsync(
+ signedOrders,
+ _.map(signedOrders, order => order.signature),
+ signedFeeOrders,
+ _.map(signedFeeOrders, order => order.signature),
+ feePercentage,
+ feeRecipientAddress,
+ {
+ value: ethAmount,
+ from: normalizedTakerAddress,
+ gas: txOpts.gasLimit,
+ gasPrice: txOpts.gasPrice,
+ },
+ );
+ return txHash;
+ }
+ /**
+ * Attempt to purchase makerAssetFillAmount of makerAsset by selling ethAmount provided with transaction.
+ * Any ZRX required to pay fees for primary orders will automatically be purchased by the contract.
+ * Any ETH not spent will be refunded to sender.
+ * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset.
+ * All orders must specify WETH as the takerAsset
+ * @param makerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill.
+ * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
+ * Provider provided at instantiation.
+ * @param ethAmount The amount of eth to send with the transaction
+ * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset.
+ * Used to purchase ZRX for primary order fees.
+ * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
+ * Defaults to 0.
+ * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled.
+ * @param txOpts Transaction parameters.
+ * @return Transaction hash.
+ */
+ public async marketBuyOrdersWithEthAsync(
+ signedOrders: SignedOrder[],
+ makerAssetFillAmount: BigNumber,
+ takerAddress: string,
+ ethAmount: BigNumber,
+ signedFeeOrders: SignedOrder[] = [],
+ feePercentage: BigNumber = constants.ZERO_AMOUNT,
+ feeRecipientAddress: string = constants.NULL_ADDRESS,
+ txOpts: TransactionOpts = {},
+ ): Promise<string> {
+ assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
+ assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount);
+ await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
+ assert.isBigNumber('ethAmount', ethAmount);
+ assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
+ assert.isBigNumber('feePercentage', feePercentage);
+ assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress);
+ assert.doesConformToSchema('txOpts', txOpts, txOptsSchema);
+ const normalizedTakerAddress = takerAddress.toLowerCase();
+ const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase();
+ const ForwarderContractInstance = await this._getForwarderContractAsync();
+ const txHash = await ForwarderContractInstance.marketBuyOrdersWithEth.sendTransactionAsync(
+ signedOrders,
+ makerAssetFillAmount,
+ _.map(signedOrders, order => order.signature),
+ signedFeeOrders,
+ _.map(signedFeeOrders, order => order.signature),
+ feePercentage,
+ feeRecipientAddress,
+ {
+ value: ethAmount,
+ from: normalizedTakerAddress,
+ gas: txOpts.gasLimit,
+ gasPrice: txOpts.gasPrice,
+ },
+ );
+ return txHash;
+ }
+ /**
+ * Retrieves the Ethereum address of the Forwarder contract deployed on the network
+ * that the user-passed web3 provider is connected to.
+ * @returns The Ethereum address of the Forwarder contract being used.
+ */
+ public getContractAddress(): string {
+ const contractAddress = this._getContractAddress(artifacts.Forwarder, this._contractAddressIfExists);
+ return contractAddress;
+ }
+ // HACK: We don't want this method to be visible to the other units within that package but not to the end user.
+ // TS doesn't give that possibility and therefore we make it private and access it over an any cast. Because of that tslint sees it as unused.
+ // tslint:disable-next-line:no-unused-variable
+ private _invalidateContractInstance(): void {
+ delete this._forwarderContractIfExists;
+ }
+ private async _getForwarderContractAsync(): Promise<ForwarderContract> {
+ if (!_.isUndefined(this._forwarderContractIfExists)) {
+ return this._forwarderContractIfExists;
+ }
+ const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
+ artifacts.Forwarder,
+ this._contractAddressIfExists,
+ );
+ const contractInstance = new ForwarderContract(
+ abi,
+ address,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ this._forwarderContractIfExists = contractInstance;
+ return this._forwarderContractIfExists;
+ }
+}
diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts
index e5485d7a6..1986e0004 100644
--- a/packages/contract-wrappers/src/index.ts
+++ b/packages/contract-wrappers/src/index.ts
@@ -5,6 +5,7 @@ export { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
export { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
+export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
export {
ContractWrappersError,
diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts
index f9d7a6b9f..887d09c80 100644
--- a/packages/contract-wrappers/src/types.ts
+++ b/packages/contract-wrappers/src/types.ts
@@ -109,6 +109,7 @@ export type SyncMethod = (...args: any[]) => any;
* zrxContractAddress: The address of the ZRX contract to use
* erc20ProxyContractAddress: The address of the erc20 token transfer proxy contract to use
* erc721ProxyContractAddress: The address of the erc721 token transfer proxy contract to use
+ * forwarderContractAddress: The address of the forwarder contract to use
* orderWatcherConfig: All the configs related to the orderWatcher
* blockPollingIntervalMs: The interval to use for block polling in event watching methods (defaults to 1000)
*/
@@ -119,6 +120,7 @@ export interface ContractWrappersConfig {
zrxContractAddress?: string;
erc20ProxyContractAddress?: string;
erc721ProxyContractAddress?: string;
+ forwarderContractAddress?: string;
blockPollingIntervalMs?: number;
}
diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts
index 039475b7f..d436efefc 100644
--- a/packages/contract-wrappers/src/utils/constants.ts
+++ b/packages/contract-wrappers/src/utils/constants.ts
@@ -10,4 +10,5 @@ export const constants = {
// tslint:disable-next-line:custom-no-magic-numbers
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
+ ZERO_AMOUNT: new BigNumber(0),
};
diff --git a/packages/contract-wrappers/test/forwarder_wrapper_test.ts b/packages/contract-wrappers/test/forwarder_wrapper_test.ts
new file mode 100644
index 000000000..61a21a0d7
--- /dev/null
+++ b/packages/contract-wrappers/test/forwarder_wrapper_test.ts
@@ -0,0 +1,57 @@
+import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
+import { FillScenarios } from '@0xproject/fill-scenarios';
+import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
+import { DoneCallback, SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import { BlockParamLiteral } from 'ethereum-types';
+import 'mocha';
+
+import {
+ ContractWrappers,
+ DecodedLogEvent,
+ ExchangeCancelEventArgs,
+ ExchangeEvents,
+ ExchangeFillEventArgs,
+ OrderStatus,
+} from '../src';
+
+import { chaiSetup } from './utils/chai_setup';
+import { constants } from './utils/constants';
+import { tokenUtils } from './utils/token_utils';
+import { provider, web3Wrapper } from './utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+
+describe('ForwarderWrapper', () => {
+ let contractWrappers: ContractWrappers;
+ let forwarderContractAddress: string;
+ let userAddresses: string[];
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ blockPollingIntervalMs: 0,
+ };
+ before(async () => {
+ await blockchainLifecycle.startAsync();
+ contractWrappers = new ContractWrappers(provider, config);
+ forwarderContractAddress = contractWrappers.exchange.getContractAddress();
+ userAddresses = await web3Wrapper.getAvailableAddressesAsync();
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ // describe('#fillOrderAsync', () => {
+ // it('should fill a valid order', async () => {
+ // // txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
+ // // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ // });
+ // });
+});