From 209266dbed9d7d038c90c2da8d9b99acab77c80c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 9 May 2018 20:36:28 +0200 Subject: Split 0x.js into contract-wrappers, order-watcher but keep 0x.js as a unifying library with the same interface --- packages/contract-wrappers/src/artifacts.ts | 18 + .../src/compact_artifacts/DummyToken.json | 22 + .../src/compact_artifacts/EtherToken.json | 287 ++++ .../src/compact_artifacts/Exchange.json | 610 ++++++++ .../src/compact_artifacts/Token.json | 172 +++ .../src/compact_artifacts/TokenRegistry.json | 547 ++++++++ .../src/compact_artifacts/TokenTransferProxy.json | 187 +++ .../src/compact_artifacts/ZRX.json | 20 + .../contract-wrappers/src/contract_wrappers.ts | 136 ++ .../src/contract_wrappers/contract_wrapper.ts | 208 +++ .../src/contract_wrappers/ether_token_wrapper.ts | 207 +++ .../src/contract_wrappers/exchange_wrapper.ts | 945 +++++++++++++ .../src/contract_wrappers/generated/dummy_token.ts | 84 ++ .../src/contract_wrappers/generated/ether_token.ts | 621 +++++++++ .../src/contract_wrappers/generated/exchange.ts | 1459 ++++++++++++++++++++ .../src/contract_wrappers/generated/token.ts | 432 ++++++ .../contract_wrappers/generated/token_registry.ts | 799 +++++++++++ .../generated/token_transfer_proxy.ts | 447 ++++++ .../contract_wrappers/token_registry_wrapper.ts | 134 ++ .../token_transfer_proxy_wrapper.ts | 75 + .../src/contract_wrappers/token_wrapper.ts | 441 ++++++ .../simple_balance_and_proxy_allowance_fetcher.ts | 28 + .../simple_order_filled_cancelled_fetcher.ts | 34 + packages/contract-wrappers/src/globals.d.ts | 6 + packages/contract-wrappers/src/index.ts | 68 + .../src/monorepo_scripts/postpublish.ts | 8 + .../src/schemas/zero_ex_contract_config_schema.ts | 5 + ...ro_ex_contract_private_network_config_schema.ts | 35 + ...ero_ex_contract_public_network_config_schema.ts | 29 + .../stores/balance_proxy_allowance_lazy_store.ts | 91 ++ .../stores/order_filled_cancelled_lazy_store.ts | 73 + packages/contract-wrappers/src/types.ts | 187 +++ packages/contract-wrappers/src/utils/assert.ts | 31 + packages/contract-wrappers/src/utils/constants.ts | 11 + packages/contract-wrappers/src/utils/decorators.ts | 91 ++ .../src/utils/exchange_transfer_simulator.ts | 115 ++ .../contract-wrappers/src/utils/filter_utils.ts | 95 ++ .../src/utils/order_validation_utils.ts | 198 +++ packages/contract-wrappers/src/utils/utils.ts | 13 + 39 files changed, 8969 insertions(+) create mode 100644 packages/contract-wrappers/src/artifacts.ts create mode 100644 packages/contract-wrappers/src/compact_artifacts/DummyToken.json create mode 100644 packages/contract-wrappers/src/compact_artifacts/EtherToken.json create mode 100644 packages/contract-wrappers/src/compact_artifacts/Exchange.json create mode 100644 packages/contract-wrappers/src/compact_artifacts/Token.json create mode 100644 packages/contract-wrappers/src/compact_artifacts/TokenRegistry.json create mode 100644 packages/contract-wrappers/src/compact_artifacts/TokenTransferProxy.json create mode 100644 packages/contract-wrappers/src/compact_artifacts/ZRX.json create mode 100644 packages/contract-wrappers/src/contract_wrappers.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/generated/dummy_token.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/generated/ether_token.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/generated/exchange.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/generated/token.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/generated/token_registry.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/generated/token_transfer_proxy.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/token_registry_wrapper.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts create mode 100644 packages/contract-wrappers/src/contract_wrappers/token_wrapper.ts create mode 100644 packages/contract-wrappers/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts create mode 100644 packages/contract-wrappers/src/fetchers/simple_order_filled_cancelled_fetcher.ts create mode 100644 packages/contract-wrappers/src/globals.d.ts create mode 100644 packages/contract-wrappers/src/index.ts create mode 100644 packages/contract-wrappers/src/monorepo_scripts/postpublish.ts create mode 100644 packages/contract-wrappers/src/schemas/zero_ex_contract_config_schema.ts create mode 100644 packages/contract-wrappers/src/schemas/zero_ex_contract_private_network_config_schema.ts create mode 100644 packages/contract-wrappers/src/schemas/zero_ex_contract_public_network_config_schema.ts create mode 100644 packages/contract-wrappers/src/stores/balance_proxy_allowance_lazy_store.ts create mode 100644 packages/contract-wrappers/src/stores/order_filled_cancelled_lazy_store.ts create mode 100644 packages/contract-wrappers/src/types.ts create mode 100644 packages/contract-wrappers/src/utils/assert.ts create mode 100644 packages/contract-wrappers/src/utils/constants.ts create mode 100644 packages/contract-wrappers/src/utils/decorators.ts create mode 100644 packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts create mode 100644 packages/contract-wrappers/src/utils/filter_utils.ts create mode 100644 packages/contract-wrappers/src/utils/order_validation_utils.ts create mode 100644 packages/contract-wrappers/src/utils/utils.ts (limited to 'packages/contract-wrappers/src') diff --git a/packages/contract-wrappers/src/artifacts.ts b/packages/contract-wrappers/src/artifacts.ts new file mode 100644 index 000000000..13587984c --- /dev/null +++ b/packages/contract-wrappers/src/artifacts.ts @@ -0,0 +1,18 @@ +import { Artifact } from '@0xproject/types'; + +import * as DummyToken from './compact_artifacts/DummyToken.json'; +import * as EtherToken from './compact_artifacts/EtherToken.json'; +import * as Exchange from './compact_artifacts/Exchange.json'; +import * as Token from './compact_artifacts/Token.json'; +import * as TokenRegistry from './compact_artifacts/TokenRegistry.json'; +import * as TokenTransferProxy from './compact_artifacts/TokenTransferProxy.json'; +import * as ZRX from './compact_artifacts/ZRX.json'; +export const artifacts = { + ZRX: (ZRX as any) as Artifact, + DummyToken: (DummyToken as any) as Artifact, + Token: (Token as any) as Artifact, + Exchange: (Exchange as any) as Artifact, + EtherToken: (EtherToken as any) as Artifact, + TokenRegistry: (TokenRegistry as any) as Artifact, + TokenTransferProxy: (TokenTransferProxy as any) as Artifact, +}; diff --git a/packages/contract-wrappers/src/compact_artifacts/DummyToken.json b/packages/contract-wrappers/src/compact_artifacts/DummyToken.json new file mode 100644 index 000000000..f64a8cd3d --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/DummyToken.json @@ -0,0 +1,22 @@ +{ + "contract_name": "DummyToken", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_target", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "setBalance", + "outputs": [], + "payable": false, + "type": "function" + } + ] +} diff --git a/packages/contract-wrappers/src/compact_artifacts/EtherToken.json b/packages/contract-wrappers/src/compact_artifacts/EtherToken.json new file mode 100644 index 000000000..26cca57cd --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/EtherToken.json @@ -0,0 +1,287 @@ +{ + "contract_name": "EtherToken", + "abi": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "deposit", + "outputs": [], + "payable": true, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "payable": true, + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "name": "_spender", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + } + ], + "networks": { + "1": { + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + }, + "3": { + "address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a" + }, + "4": { + "address": "0xc778417e063141139fce010982780140aa0cd5ab" + }, + "42": { + "address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1" + }, + "50": { + "address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c" + } + } +} diff --git a/packages/contract-wrappers/src/compact_artifacts/Exchange.json b/packages/contract-wrappers/src/compact_artifacts/Exchange.json new file mode 100644 index 000000000..af8db7360 --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/Exchange.json @@ -0,0 +1,610 @@ +{ + "contract_name": "Exchange", + "abi": [ + { + "constant": true, + "inputs": [ + { + "name": "numerator", + "type": "uint256" + }, + { + "name": "denominator", + "type": "uint256" + }, + { + "name": "target", + "type": "uint256" + } + ], + "name": "isRoundingError", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "filled", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "cancelled", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "fillTakerTokenAmount", + "type": "uint256" + }, + { + "name": "shouldThrowOnInsufficientBalanceOrAllowance", + "type": "bool" + }, + { + "name": "v", + "type": "uint8[]" + }, + { + "name": "r", + "type": "bytes32[]" + }, + { + "name": "s", + "type": "bytes32[]" + } + ], + "name": "fillOrdersUpTo", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + }, + { + "name": "cancelTakerTokenAmount", + "type": "uint256" + } + ], + "name": "cancelOrder", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ZRX_TOKEN_CONTRACT", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "fillTakerTokenAmounts", + "type": "uint256[]" + }, + { + "name": "v", + "type": "uint8[]" + }, + { + "name": "r", + "type": "bytes32[]" + }, + { + "name": "s", + "type": "bytes32[]" + } + ], + "name": "batchFillOrKillOrders", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + }, + { + "name": "fillTakerTokenAmount", + "type": "uint256" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "fillOrKillOrder", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "getUnavailableTakerTokenAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "signer", + "type": "address" + }, + { + "name": "hash", + "type": "bytes32" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "numerator", + "type": "uint256" + }, + { + "name": "denominator", + "type": "uint256" + }, + { + "name": "target", + "type": "uint256" + } + ], + "name": "getPartialAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "TOKEN_TRANSFER_PROXY_CONTRACT", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "fillTakerTokenAmounts", + "type": "uint256[]" + }, + { + "name": "shouldThrowOnInsufficientBalanceOrAllowance", + "type": "bool" + }, + { + "name": "v", + "type": "uint8[]" + }, + { + "name": "r", + "type": "bytes32[]" + }, + { + "name": "s", + "type": "bytes32[]" + } + ], + "name": "batchFillOrders", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5][]" + }, + { + "name": "orderValues", + "type": "uint256[6][]" + }, + { + "name": "cancelTakerTokenAmounts", + "type": "uint256[]" + } + ], + "name": "batchCancelOrders", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + }, + { + "name": "fillTakerTokenAmount", + "type": "uint256" + }, + { + "name": "shouldThrowOnInsufficientBalanceOrAllowance", + "type": "bool" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "fillOrder", + "outputs": [ + { + "name": "filledTakerTokenAmount", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "orderAddresses", + "type": "address[5]" + }, + { + "name": "orderValues", + "type": "uint256[6]" + } + ], + "name": "getOrderHash", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EXTERNAL_QUERY_GAS_LIMIT", + "outputs": [ + { + "name": "", + "type": "uint16" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "type": "function" + }, + { + "inputs": [ + { + "name": "_zrxToken", + "type": "address" + }, + { + "name": "_tokenTransferProxy", + "type": "address" + } + ], + "payable": false, + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "maker", + "type": "address" + }, + { + "indexed": false, + "name": "taker", + "type": "address" + }, + { + "indexed": true, + "name": "feeRecipient", + "type": "address" + }, + { + "indexed": false, + "name": "makerToken", + "type": "address" + }, + { + "indexed": false, + "name": "takerToken", + "type": "address" + }, + { + "indexed": false, + "name": "filledMakerTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "filledTakerTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "paidMakerFee", + "type": "uint256" + }, + { + "indexed": false, + "name": "paidTakerFee", + "type": "uint256" + }, + { + "indexed": true, + "name": "tokens", + "type": "bytes32" + }, + { + "indexed": false, + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "LogFill", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "maker", + "type": "address" + }, + { + "indexed": true, + "name": "feeRecipient", + "type": "address" + }, + { + "indexed": false, + "name": "makerToken", + "type": "address" + }, + { + "indexed": false, + "name": "takerToken", + "type": "address" + }, + { + "indexed": false, + "name": "cancelledMakerTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cancelledTakerTokenAmount", + "type": "uint256" + }, + { + "indexed": true, + "name": "tokens", + "type": "bytes32" + }, + { + "indexed": false, + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "LogCancel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "errorId", + "type": "uint8" + }, + { + "indexed": true, + "name": "orderHash", + "type": "bytes32" + } + ], + "name": "LogError", + "type": "event" + } + ], + "networks": { + "1": { + "address": "0x12459c951127e0c374ff9105dda097662a027093" + }, + "3": { + "address": "0x479cc461fecd078f766ecc58533d6f69580cf3ac" + }, + "4": { + "address": "0x1d16ef40fac01cec8adac2ac49427b9384192c05" + }, + "42": { + "address": "0x90fe2af704b34e0224bf2299c838e04d4dcf1364" + }, + "50": { + "address": "0x48bacb9266a570d521063ef5dd96e61686dbe788" + } + } +} diff --git a/packages/contract-wrappers/src/compact_artifacts/Token.json b/packages/contract-wrappers/src/compact_artifacts/Token.json new file mode 100644 index 000000000..3b5a86ae0 --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/Token.json @@ -0,0 +1,172 @@ +{ + "contract_name": "Token", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "supply", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "remaining", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "name": "_spender", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + } + ] +} diff --git a/packages/contract-wrappers/src/compact_artifacts/TokenRegistry.json b/packages/contract-wrappers/src/compact_artifacts/TokenRegistry.json new file mode 100644 index 000000000..0f583628c --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/TokenRegistry.json @@ -0,0 +1,547 @@ +{ + "contract_name": "TokenRegistry", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_index", + "type": "uint256" + } + ], + "name": "removeToken", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_name", + "type": "string" + } + ], + "name": "getTokenAddressByName", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_symbol", + "type": "string" + } + ], + "name": "getTokenAddressBySymbol", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_swarmHash", + "type": "bytes" + } + ], + "name": "setTokenSwarmHash", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "getTokenMetaData", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "uint8" + }, + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_name", + "type": "string" + }, + { + "name": "_symbol", + "type": "string" + }, + { + "name": "_decimals", + "type": "uint8" + }, + { + "name": "_ipfsHash", + "type": "bytes" + }, + { + "name": "_swarmHash", + "type": "bytes" + } + ], + "name": "addToken", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_name", + "type": "string" + } + ], + "name": "setTokenName", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "tokens", + "outputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "symbol", + "type": "string" + }, + { + "name": "decimals", + "type": "uint8" + }, + { + "name": "ipfsHash", + "type": "bytes" + }, + { + "name": "swarmHash", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "tokenAddresses", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_name", + "type": "string" + } + ], + "name": "getTokenByName", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "uint8" + }, + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getTokenAddresses", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_ipfsHash", + "type": "bytes" + } + ], + "name": "setTokenIpfsHash", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_symbol", + "type": "string" + } + ], + "name": "getTokenBySymbol", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "string" + }, + { + "name": "", + "type": "uint8" + }, + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + }, + { + "name": "_symbol", + "type": "string" + } + ], + "name": "setTokenSymbol", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "name", + "type": "string" + }, + { + "indexed": false, + "name": "symbol", + "type": "string" + }, + { + "indexed": false, + "name": "decimals", + "type": "uint8" + }, + { + "indexed": false, + "name": "ipfsHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "swarmHash", + "type": "bytes" + } + ], + "name": "LogAddToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "name", + "type": "string" + }, + { + "indexed": false, + "name": "symbol", + "type": "string" + }, + { + "indexed": false, + "name": "decimals", + "type": "uint8" + }, + { + "indexed": false, + "name": "ipfsHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "swarmHash", + "type": "bytes" + } + ], + "name": "LogRemoveToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldName", + "type": "string" + }, + { + "indexed": false, + "name": "newName", + "type": "string" + } + ], + "name": "LogTokenNameChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldSymbol", + "type": "string" + }, + { + "indexed": false, + "name": "newSymbol", + "type": "string" + } + ], + "name": "LogTokenSymbolChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldIpfsHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "newIpfsHash", + "type": "bytes" + } + ], + "name": "LogTokenIpfsHashChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "oldSwarmHash", + "type": "bytes" + }, + { + "indexed": false, + "name": "newSwarmHash", + "type": "bytes" + } + ], + "name": "LogTokenSwarmHashChange", + "type": "event" + } + ], + "networks": { + "1": { + "address": "0x926a74c5c36adf004c87399e65f75628b0f98d2c" + }, + "3": { + "address": "0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed" + }, + "4": { + "address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6" + }, + "42": { + "address": "0xf18e504561f4347bea557f3d4558f559dddbae7f" + }, + "50": { + "address": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082" + } + } +} diff --git a/packages/contract-wrappers/src/compact_artifacts/TokenTransferProxy.json b/packages/contract-wrappers/src/compact_artifacts/TokenTransferProxy.json new file mode 100644 index 000000000..8cf551ddb --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/TokenTransferProxy.json @@ -0,0 +1,187 @@ +{ + "contract_name": "TokenTransferProxy", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "token", + "type": "address" + }, + { + "name": "from", + "type": "address" + }, + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + } + ], + "name": "addAuthorizedAddress", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "authorities", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + } + ], + "name": "removeAuthorizedAddress", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "authorized", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getAuthorizedAddresses", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": true, + "name": "caller", + "type": "address" + } + ], + "name": "LogAuthorizedAddressAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": true, + "name": "caller", + "type": "address" + } + ], + "name": "LogAuthorizedAddressRemoved", + "type": "event" + } + ], + "networks": { + "1": { + "address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4" + }, + "3": { + "address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6" + }, + "4": { + "address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d" + }, + "42": { + "address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4" + }, + "50": { + "address": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48" + } + } +} diff --git a/packages/contract-wrappers/src/compact_artifacts/ZRX.json b/packages/contract-wrappers/src/compact_artifacts/ZRX.json new file mode 100644 index 000000000..e40b8f268 --- /dev/null +++ b/packages/contract-wrappers/src/compact_artifacts/ZRX.json @@ -0,0 +1,20 @@ +{ + "contract_name": "ZRX", + "networks": { + "1": { + "address": "0xe41d2489571d322189246dafa5ebde1f4699f498" + }, + "3": { + "address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d" + }, + "4": { + "address": "0x00f58d6d585f84b2d7267940cede30ce2fe6eae8" + }, + "42": { + "address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570" + }, + "50": { + "address": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401" + } + } +} diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts new file mode 100644 index 000000000..1934ea2d0 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -0,0 +1,136 @@ +import { schemas, SchemaValidator } from '@0xproject/json-schemas'; +import { + generatePseudoRandomSalt, + getOrderHashHex, + isValidOrderHash, + isValidSignature, + signOrderHashAsync, +} from '@0xproject/order-utils'; +import { ECSignature, Order, Provider, SignedOrder, TransactionReceiptWithDecodedLogs } from '@0xproject/types'; +import { AbiDecoder, BigNumber, intervalUtils } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; + +import { artifacts } from './artifacts'; +import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper'; +import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper'; +import { TokenRegistryWrapper } from './contract_wrappers/token_registry_wrapper'; +import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_proxy_wrapper'; +import { TokenWrapper } from './contract_wrappers/token_wrapper'; +import { zeroExContractConfigSchema } from './schemas/zero_ex_contract_config_schema'; +import { zeroExContractPrivateNetworkConfigSchema } from './schemas/zero_ex_contract_private_network_config_schema'; +import { zeroExContractPublicNetworkConfigSchema } from './schemas/zero_ex_contract_public_network_config_schema'; +import { ZeroExContractConfig } from './types'; +import { assert } from './utils/assert'; +import { constants } from './utils/constants'; +import { decorators } from './utils/decorators'; +import { utils } from './utils/utils'; + +/** + * The ContractWrappers class contains smart contract wrappers helpful when building on 0x protocol. + */ +export class ContractWrappers { + /** + * An instance of the ExchangeWrapper class containing methods for interacting with the 0x Exchange smart contract. + */ + public exchange: ExchangeWrapper; + /** + * An instance of the TokenRegistryWrapper class containing methods for interacting with the 0x + * TokenRegistry smart contract. + */ + public tokenRegistry: TokenRegistryWrapper; + /** + * An instance of the TokenWrapper class containing methods for interacting with any ERC20 token smart contract. + */ + public token: TokenWrapper; + /** + * An instance of the EtherTokenWrapper class containing methods for interacting with the + * wrapped ETH ERC20 token smart contract. + */ + public etherToken: EtherTokenWrapper; + /** + * An instance of the TokenTransferProxyWrapper class containing methods for interacting with the + * tokenTransferProxy smart contract. + */ + public proxy: TokenTransferProxyWrapper; + private _web3Wrapper: Web3Wrapper; + /** + * Instantiates a new ContractWrappers instance. + * @param provider The Provider instance you would like the 0x.js library to use for interacting with + * the Ethereum network. + * @param config The configuration object. Look up the type for the description. + * @return An instance of the ContractWrappers class. + */ + constructor(provider: Provider, config: ZeroExContractConfig) { + assert.isWeb3Provider('provider', provider); + assert.doesConformToSchema('config', config, zeroExContractConfigSchema, [ + zeroExContractPrivateNetworkConfigSchema, + zeroExContractPublicNetworkConfigSchema, + ]); + const artifactJSONs = _.values(artifacts); + const abiArrays = _.map(artifactJSONs, artifact => artifact.abi); + const defaults = { + gasPrice: config.gasPrice, + }; + this._web3Wrapper = new Web3Wrapper(provider, defaults); + _.forEach(abiArrays, abi => { + this._web3Wrapper.abiDecoder.addABI(abi); + }); + this.proxy = new TokenTransferProxyWrapper( + this._web3Wrapper, + config.networkId, + config.tokenTransferProxyContractAddress, + ); + this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this.proxy); + this.exchange = new ExchangeWrapper( + this._web3Wrapper, + config.networkId, + this.token, + config.exchangeContractAddress, + config.zrxContractAddress, + ); + this.tokenRegistry = new TokenRegistryWrapper( + this._web3Wrapper, + config.networkId, + config.tokenRegistryContractAddress, + ); + this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this.token); + } + /** + * Sets a new web3 provider for 0x.js. Updating the provider will stop all + * subscriptions so you will need to re-subscribe to all events relevant to your app after this call. + * @param provider The Web3Provider you would like the 0x.js library to use from now on. + * @param networkId The id of the network your provider is connected to + */ + public setProvider(provider: Provider, networkId: number): void { + this._web3Wrapper.setProvider(provider); + (this.exchange as any)._invalidateContractInstances(); + (this.exchange as any)._setNetworkId(networkId); + (this.tokenRegistry as any)._invalidateContractInstance(); + (this.tokenRegistry as any)._setNetworkId(networkId); + (this.token as any)._invalidateContractInstances(); + (this.token as any)._setNetworkId(networkId); + (this.proxy as any)._invalidateContractInstance(); + (this.proxy as any)._setNetworkId(networkId); + (this.etherToken as any)._invalidateContractInstance(); + (this.etherToken as any)._setNetworkId(networkId); + } + /** + * Get the provider instance currently used by 0x.js + * @return Web3 provider instance + */ + public getProvider(): Provider { + return this._web3Wrapper.getProvider(); + } + /* + * HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from + * an `ExchangeWrapper`. `ExchangeWrapper` needs `TokenWrapper` to validate orders, creating a dependency cycle. + * In order to break this - we create this function here and pass it as a parameter to the `TokenWrapper` + * and `ProxyWrapper`. + */ + private async _getTokenTransferProxyAddressAsync(): Promise { + const tokenTransferProxyAddress = await (this.exchange as any)._getTokenTransferProxyAddressAsync(); + return tokenTransferProxyAddress; + } +} diff --git a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts new file mode 100644 index 000000000..f255ced62 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts @@ -0,0 +1,208 @@ +import { + Artifact, + BlockParamLiteral, + ContractAbi, + FilterObject, + LogEntry, + LogWithDecodedArgs, + RawLog, +} from '@0xproject/types'; +import { AbiDecoder, intervalUtils } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream'; +import * as _ from 'lodash'; + +import { + BlockRange, + ContractEventArgs, + ContractEvents, + ContractWrappersError, + EventCallback, + IndexedFilterValues, + InternalContractWrappersError, +} from '../types'; +import { constants } from '../utils/constants'; +import { filterUtils } from '../utils/filter_utils'; + +const CONTRACT_NAME_TO_NOT_FOUND_ERROR: { + [contractName: string]: ContractWrappersError; +} = { + ZRX: ContractWrappersError.ZRXContractDoesNotExist, + EtherToken: ContractWrappersError.EtherTokenContractDoesNotExist, + Token: ContractWrappersError.TokenContractDoesNotExist, + TokenRegistry: ContractWrappersError.TokenRegistryContractDoesNotExist, + TokenTransferProxy: ContractWrappersError.TokenTransferProxyContractDoesNotExist, + Exchange: ContractWrappersError.ExchangeContractDoesNotExist, +}; + +export class ContractWrapper { + protected _web3Wrapper: Web3Wrapper; + protected _networkId: number; + private _blockAndLogStreamerIfExists?: BlockAndLogStreamer; + private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer; + private _filters: { [filterToken: string]: FilterObject }; + private _filterCallbacks: { + [filterToken: string]: EventCallback; + }; + private _onLogAddedSubscriptionToken: string | undefined; + private _onLogRemovedSubscriptionToken: string | undefined; + constructor(web3Wrapper: Web3Wrapper, networkId: number) { + this._web3Wrapper = web3Wrapper; + this._networkId = networkId; + this._filters = {}; + this._filterCallbacks = {}; + this._blockAndLogStreamerIfExists = undefined; + this._onLogAddedSubscriptionToken = undefined; + this._onLogRemovedSubscriptionToken = undefined; + } + protected _unsubscribeAll(): void { + const filterTokens = _.keys(this._filterCallbacks); + _.each(filterTokens, filterToken => { + this._unsubscribe(filterToken); + }); + } + protected _unsubscribe(filterToken: string, err?: Error): void { + if (_.isUndefined(this._filters[filterToken])) { + throw new Error(ContractWrappersError.SubscriptionNotFound); + } + if (!_.isUndefined(err)) { + const callback = this._filterCallbacks[filterToken]; + callback(err, undefined); + } + delete this._filters[filterToken]; + delete this._filterCallbacks[filterToken]; + if (_.isEmpty(this._filters)) { + this._stopBlockAndLogStream(); + } + } + protected _subscribe( + address: string, + eventName: ContractEvents, + indexFilterValues: IndexedFilterValues, + abi: ContractAbi, + callback: EventCallback, + ): string { + const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi); + if (_.isUndefined(this._blockAndLogStreamerIfExists)) { + this._startBlockAndLogStream(); + } + const filterToken = filterUtils.generateUUID(); + this._filters[filterToken] = filter; + this._filterCallbacks[filterToken] = callback as EventCallback; + return filterToken; + } + protected async _getLogsAsync( + address: string, + eventName: ContractEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + abi: ContractAbi, + ): Promise>> { + const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange); + const logs = await this._web3Wrapper.getLogsAsync(filter); + const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this)); + return logsWithDecodedArguments; + } + protected _tryToDecodeLogOrNoop( + log: LogEntry, + ): LogWithDecodedArgs | RawLog { + if (_.isUndefined(this._web3Wrapper.abiDecoder)) { + throw new Error(InternalContractWrappersError.NoAbiDecoder); + } + const logWithDecodedArgs = this._web3Wrapper.abiDecoder.tryToDecodeLogOrNoop(log); + return logWithDecodedArgs; + } + protected async _getContractAbiAndAddressFromArtifactsAsync( + artifact: Artifact, + addressIfExists?: string, + ): Promise<[ContractAbi, string]> { + let contractAddress: string; + if (_.isUndefined(addressIfExists)) { + if (_.isUndefined(artifact.networks[this._networkId])) { + throw new Error(ContractWrappersError.ContractNotDeployedOnNetwork); + } + contractAddress = artifact.networks[this._networkId].address.toLowerCase(); + } else { + contractAddress = addressIfExists; + } + const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(contractAddress); + if (!doesContractExist) { + throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]); + } + const abiAndAddress: [ContractAbi, string] = [artifact.abi, contractAddress]; + return abiAndAddress; + } + protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string { + if (_.isUndefined(addressIfExists)) { + const contractAddress = artifact.networks[this._networkId].address; + if (_.isUndefined(contractAddress)) { + throw new Error(ContractWrappersError.ExchangeContractDoesNotExist); + } + return contractAddress; + } else { + return addressIfExists; + } + } + private _onLogStateChanged(isRemoved: boolean, log: LogEntry): void { + _.forEach(this._filters, (filter: FilterObject, filterToken: string) => { + if (filterUtils.matchesFilter(log, filter)) { + const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs; + const logEvent = { + log: decodedLog, + isRemoved, + }; + this._filterCallbacks[filterToken](null, logEvent); + } + }); + } + private _startBlockAndLogStream(): void { + if (!_.isUndefined(this._blockAndLogStreamerIfExists)) { + throw new Error(ContractWrappersError.SubscriptionAlreadyPresent); + } + this._blockAndLogStreamerIfExists = new BlockAndLogStreamer( + this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper), + this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper), + ); + const catchAllLogFilter = {}; + this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter); + this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval( + this._reconcileBlockAsync.bind(this), + constants.DEFAULT_BLOCK_POLLING_INTERVAL, + this._onReconcileBlockError.bind(this), + ); + let isRemoved = false; + this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded( + this._onLogStateChanged.bind(this, isRemoved), + ); + isRemoved = true; + this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved( + this._onLogStateChanged.bind(this, isRemoved), + ); + } + private _onReconcileBlockError(err: Error): void { + const filterTokens = _.keys(this._filterCallbacks); + _.each(filterTokens, filterToken => { + this._unsubscribe(filterToken, err); + }); + } + private _setNetworkId(networkId: number): void { + this._networkId = networkId; + } + private _stopBlockAndLogStream(): void { + if (_.isUndefined(this._blockAndLogStreamerIfExists)) { + throw new Error(ContractWrappersError.SubscriptionNotFound); + } + this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string); + this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string); + intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamIntervalIfExists as NodeJS.Timer); + delete this._blockAndLogStreamerIfExists; + } + private async _reconcileBlockAsync(): Promise { + const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest); + // We need to coerce to Block type cause Web3.Block includes types for mempool blocks + if (!_.isUndefined(this._blockAndLogStreamerIfExists)) { + // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined + await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block); + } + } +} diff --git a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts new file mode 100644 index 000000000..1bd65270b --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts @@ -0,0 +1,207 @@ +import { schemas } from '@0xproject/json-schemas'; +import { LogWithDecodedArgs } from '@0xproject/types'; +import { AbiDecoder, BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { artifacts } from '../artifacts'; +import { BlockRange, ContractWrappersError, EventCallback, IndexedFilterValues, TransactionOpts } from '../types'; +import { assert } from '../utils/assert'; + +import { ContractWrapper } from './contract_wrapper'; +import { EtherTokenContract, EtherTokenContractEventArgs, EtherTokenEvents } from './generated/ether_token'; +import { TokenWrapper } from './token_wrapper'; + +/** + * This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract. + * The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back. + */ +export class EtherTokenWrapper extends ContractWrapper { + private _etherTokenContractsByAddress: { + [address: string]: EtherTokenContract; + } = {}; + private _tokenWrapper: TokenWrapper; + constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenWrapper: TokenWrapper) { + super(web3Wrapper, networkId); + this._tokenWrapper = tokenWrapper; + } + /** + * Deposit ETH into the Wrapped ETH smart contract and issues the equivalent number of wrapped ETH tokens + * to the depositor address. These wrapped ETH tokens can be used in 0x trades and are redeemable for 1-to-1 + * for ETH. + * @param etherTokenAddress EtherToken address you wish to deposit into. + * @param amountInWei Amount of ETH in Wei the caller wishes to deposit. + * @param depositor The hex encoded user Ethereum address that would like to make the deposit. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async depositAsync( + etherTokenAddress: string, + amountInWei: BigNumber, + depositor: string, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + assert.isValidBaseUnitAmount('amountInWei', amountInWei); + await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); + const normalizedDepositorAddress = depositor.toLowerCase(); + + const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress); + assert.assert(ethBalanceInWei.gte(amountInWei), ContractWrappersError.InsufficientEthBalanceForDeposit); + + const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress); + const txHash = await wethContract.deposit.sendTransactionAsync({ + from: normalizedDepositorAddress, + value: amountInWei, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, + }); + return txHash; + } + /** + * Withdraw ETH to the withdrawer's address from the wrapped ETH smart contract in exchange for the + * equivalent number of wrapped ETH tokens. + * @param etherTokenAddress EtherToken address you wish to withdraw from. + * @param amountInWei Amount of ETH in Wei the caller wishes to withdraw. + * @param withdrawer The hex encoded user Ethereum address that would like to make the withdrawal. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async withdrawAsync( + etherTokenAddress: string, + amountInWei: BigNumber, + withdrawer: string, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isValidBaseUnitAmount('amountInWei', amountInWei); + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); + const normalizedWithdrawerAddress = withdrawer.toLowerCase(); + + const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync( + normalizedEtherTokenAddress, + normalizedWithdrawerAddress, + ); + assert.assert( + WETHBalanceInBaseUnits.gte(amountInWei), + ContractWrappersError.InsufficientWEthBalanceForWithdrawal, + ); + + const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress); + const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, { + from: normalizedWithdrawerAddress, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, + }); + return txHash; + } + /** + * Gets historical logs without creating a subscription + * @param etherTokenAddress An address of the ether token that emitted the logs. + * @param eventName The ether token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + etherTokenAddress: string, + eventName: EtherTokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); + assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._getLogsAsync( + normalizedEtherTokenAddress, + eventName, + blockRange, + indexFilterValues, + artifacts.EtherToken.abi, + ); + return logs; + } + /** + * Subscribe to an event type emitted by the Token contract. + * @param etherTokenAddress The hex encoded address where the ether token is deployed. + * @param eventName The ether token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @return Subscription token used later to unsubscribe + */ + public subscribe( + etherTokenAddress: string, + eventName: EtherTokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + ): string { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); + assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscribe( + normalizedEtherTokenAddress, + eventName, + indexFilterValues, + artifacts.EtherToken.abi, + callback, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super._unsubscribeAll(); + } + /** + * Retrieves the Ethereum address of the EtherToken contract deployed on the network + * that the user-passed web3 provider is connected to. If it's not Kovan, Ropsten, Rinkeby, Mainnet or TestRPC + * (networkId: 50), it will return undefined (e.g a private network). + * @returns The Ethereum address of the EtherToken contract or undefined. + */ + public getContractAddressIfExists(): string | undefined { + const networkSpecificArtifact = artifacts.EtherToken.networks[this._networkId]; + const contractAddressIfExists = _.isUndefined(networkSpecificArtifact) + ? undefined + : networkSpecificArtifact.address; + return contractAddressIfExists; + } + private _invalidateContractInstance(): void { + this.unsubscribeAll(); + this._etherTokenContractsByAddress = {}; + } + private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise { + let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress]; + if (!_.isUndefined(etherTokenContract)) { + return etherTokenContract; + } + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( + artifacts.EtherToken, + etherTokenAddress, + ); + const contractInstance = new EtherTokenContract( + abi, + address, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + etherTokenContract = contractInstance; + this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract; + return etherTokenContract; + } +} diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts new file mode 100644 index 000000000..f2b64fc37 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts @@ -0,0 +1,945 @@ +import { schemas } from '@0xproject/json-schemas'; +import { formatters, getOrderHashHex, OrderStateUtils } from '@0xproject/order-utils'; +import { + BlockParamLiteral, + DecodedLogArgs, + ECSignature, + ExchangeContractErrs, + LogEntry, + LogWithDecodedArgs, + Order, + OrderAddresses, + OrderState, + OrderValues, + SignedOrder, +} from '@0xproject/types'; +import { AbiDecoder, BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { artifacts } from '../artifacts'; +import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher'; +import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher'; +import { + BlockRange, + EventCallback, + ExchangeContractErrCodes, + IndexedFilterValues, + MethodOpts, + OrderCancellationRequest, + OrderFillRequest, + OrderTransactionOpts, + ValidateOrderFillableOpts, +} from '../types'; +import { assert } from '../utils/assert'; +import { decorators } from '../utils/decorators'; +import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator'; +import { OrderValidationUtils } from '../utils/order_validation_utils'; +import { utils } from '../utils/utils'; + +import { ContractWrapper } from './contract_wrapper'; +import { + ExchangeContract, + ExchangeContractEventArgs, + ExchangeEvents, + LogErrorContractEventArgs, +} from './generated/exchange'; +import { TokenWrapper } from './token_wrapper'; +const SHOULD_VALIDATE_BY_DEFAULT = true; + +interface ExchangeContractErrCodesToMsgs { + [exchangeContractErrCodes: number]: string; +} + +/** + * This class includes all the functionality related to calling methods and subscribing to + * events of the 0x Exchange smart contract. + */ +export class ExchangeWrapper extends ContractWrapper { + private _exchangeContractIfExists?: ExchangeContract; + private _orderValidationUtils: OrderValidationUtils; + private _tokenWrapper: TokenWrapper; + private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = { + [ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired, + [ExchangeContractErrCodes.ERROR_CANCEL_EXPIRED]: ExchangeContractErrs.OrderFillExpired, + [ExchangeContractErrCodes.ERROR_FILL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero, + [ExchangeContractErrCodes.ERROR_CANCEL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero, + [ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.OrderFillRoundingError, + [ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.FillBalanceAllowanceError, + }; + private _contractAddressIfExists?: string; + private _zrxContractAddressIfExists?: string; + constructor( + web3Wrapper: Web3Wrapper, + networkId: number, + tokenWrapper: TokenWrapper, + contractAddressIfExists?: string, + zrxContractAddressIfExists?: string, + ) { + super(web3Wrapper, networkId); + this._tokenWrapper = tokenWrapper; + this._orderValidationUtils = new OrderValidationUtils(this); + this._contractAddressIfExists = contractAddressIfExists; + this._zrxContractAddressIfExists = zrxContractAddressIfExists; + } + /** + * Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total + * amount that has been filled or cancelled. The remaining takerAmount can be calculated by + * subtracting the unavailable amount from the total order takerAmount. + * @param orderHash The hex encoded orderHash for which you would like to retrieve the + * unavailable takerAmount. + * @param methodOpts Optional arguments this method accepts. + * @return The amount of the order (in taker tokens) that has either been filled or cancelled. + */ + public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise { + assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); + + const exchangeContract = await this._getExchangeContractAsync(); + const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; + const txData = {}; + let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync( + orderHash, + txData, + defaultBlock, + ); + // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber + unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount); + return unavailableTakerTokenAmount; + } + /** + * Retrieve the takerAmount of an order that has already been filled. + * @param orderHash The hex encoded orderHash for which you would like to retrieve the filled takerAmount. + * @param methodOpts Optional arguments this method accepts. + * @return The amount of the order (in taker tokens) that has already been filled. + */ + public async getFilledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise { + assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); + + const exchangeContract = await this._getExchangeContractAsync(); + const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; + const txData = {}; + let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, txData, defaultBlock); + // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber + fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits); + return fillAmountInBaseUnits; + } + /** + * Retrieve the takerAmount of an order that has been cancelled. + * @param orderHash The hex encoded orderHash for which you would like to retrieve the + * cancelled takerAmount. + * @param methodOpts Optional arguments this method accepts. + * @return The amount of the order (in taker tokens) that has been cancelled. + */ + public async getCancelledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise { + assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); + + const exchangeContract = await this._getExchangeContractAsync(); + const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; + const txData = {}; + let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, txData, defaultBlock); + // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber + cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits); + return cancelledAmountInBaseUnits; + } + /** + * Fills a signed order with an amount denominated in baseUnits of the taker token. + * Since the order in which transactions are included in the next block is indeterminate, race-conditions + * could arise where a users balance or allowance changes before the fillOrder executes. Because of this, + * we allow you to specify `shouldThrowOnInsufficientBalanceOrAllowance`. + * If false, the smart contract will not throw if the parties + * do not have sufficient balances/allowances, preserving gas costs. Setting it to true forgoes this check + * and causes the smart contract to throw (using all the gas supplied) instead. + * @param signedOrder An object that conforms to the SignedOrder interface. + * @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that + * you wish to fill. + * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw + * if upon execution the tokens cannot be transferred. + * @param takerAddress The user Ethereum address who would like to fill this order. + * Must be available via the supplied Provider + * passed to 0x.js. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async fillOrderAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); + assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + + const exchangeInstance = await this._getExchangeContractAsync(); + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + normalizedTakerAddress, + zrxTokenAddress, + ); + } + + const [orderAddresses, orderValues] = formatters.getOrderAddressesAndValues(signedOrder); + + const txHash: string = await exchangeInstance.fillOrder.sendTransactionAsync( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + signedOrder.ecSignature.v, + signedOrder.ecSignature.r, + signedOrder.ecSignature.s, + { + from: normalizedTakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Sequentially and atomically fills signedOrders up to the specified takerTokenFillAmount. + * If the fill amount is reached - it succeeds and does not fill the rest of the orders. + * If fill amount is not reached - it fills as much of the fill amount as possible and succeeds. + * @param signedOrders The array of signedOrders that you would like to fill until + * takerTokenFillAmount is reached. + * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill. + * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw if + * upon execution any of the tokens cannot be transferred. + * If set to false, the call will continue to fill subsequent + * signedOrders even when some cannot be filled. + * @param takerAddress The user Ethereum address who would like to fill these + * orders. Must be available via the supplied Provider + * passed to 0x.js. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async fillOrdersUpToAsync( + signedOrders: SignedOrder[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress); + assert.hasAtMostOneUniqueValue( + takerTokenAddresses, + ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed, + ); + const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); + assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); + assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + let filledTakerTokenAmount = new BigNumber(0); + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + for (const signedOrder of signedOrders) { + const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount.minus(filledTakerTokenAmount), + normalizedTakerAddress, + zrxTokenAddress, + ); + filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount); + if (filledTakerTokenAmount.eq(fillTakerTokenAmount)) { + break; + } + } + } + + if (_.isEmpty(signedOrders)) { + throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); + } + + const orderAddressesValuesAndSignatureArray = _.map(signedOrders, signedOrder => { + return [ + ...formatters.getOrderAddressesAndValues(signedOrder), + signedOrder.ecSignature.v, + signedOrder.ecSignature.r, + signedOrder.ecSignature.s, + ]; + }); + // We use _.unzip because _.unzip doesn't type check if values have different types :'( + const [orderAddressesArray, orderValuesArray, vArray, rArray, sArray] = _.unzip( + orderAddressesValuesAndSignatureArray, + ); + + const exchangeInstance = await this._getExchangeContractAsync(); + const txHash = await exchangeInstance.fillOrdersUpTo.sendTransactionAsync( + orderAddressesArray, + orderValuesArray, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + vArray, + rArray, + sArray, + { + from: normalizedTakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Batch version of fillOrderAsync. + * Executes multiple fills atomically in a single transaction. + * If shouldThrowOnInsufficientBalanceOrAllowance is set to false, it will continue filling subsequent orders even + * when earlier ones fail. + * When shouldThrowOnInsufficientBalanceOrAllowance is set to true, if any fill fails, the entire batch fails. + * @param orderFillRequests An array of objects that conform to the + * OrderFillRequest interface. + * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw + * if upon execution any of the tokens cannot be + * transferred. If set to false, the call will continue to + * fill subsequent signedOrders even when some + * cannot be filled. + * @param takerAddress The user Ethereum address who would like to fill + * these orders. Must be available via the supplied + * Provider passed to 0x.js. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchFillOrdersAsync( + orderFillRequests: OrderFillRequest[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); + const exchangeContractAddresses = _.map( + orderFillRequests, + orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, + ); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); + assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + for (const orderFillRequest of orderFillRequests) { + await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + orderFillRequest.signedOrder, + orderFillRequest.takerTokenFillAmount, + normalizedTakerAddress, + zrxTokenAddress, + ); + } + } + if (_.isEmpty(orderFillRequests)) { + throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); + } + + const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => { + return [ + ...formatters.getOrderAddressesAndValues(orderFillRequest.signedOrder), + orderFillRequest.takerTokenFillAmount, + orderFillRequest.signedOrder.ecSignature.v, + orderFillRequest.signedOrder.ecSignature.r, + orderFillRequest.signedOrder.ecSignature.s, + ]; + }); + // We use _.unzip because _.unzip doesn't type check if values have different types :'( + const [orderAddressesArray, orderValuesArray, fillTakerTokenAmounts, vArray, rArray, sArray] = _.unzip( + orderAddressesValuesAmountsAndSignatureArray, + ); + + const exchangeInstance = await this._getExchangeContractAsync(); + const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync( + orderAddressesArray, + orderValuesArray, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + vArray, + rArray, + sArray, + { + from: normalizedTakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled, + * the fill order is abandoned. + * @param signedOrder An object that conforms to the SignedOrder interface. The + * signedOrder you wish to fill. + * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill. + * @param takerAddress The user Ethereum address who would like to fill this order. + * Must be available via the supplied Provider passed to 0x.js. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async fillOrKillOrderAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + + const exchangeInstance = await this._getExchangeContractAsync(); + + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + normalizedTakerAddress, + zrxTokenAddress, + ); + } + + const [orderAddresses, orderValues] = formatters.getOrderAddressesAndValues(signedOrder); + const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync( + orderAddresses, + orderValues, + fillTakerTokenAmount, + signedOrder.ecSignature.v, + signedOrder.ecSignature.r, + signedOrder.ecSignature.s, + { + from: normalizedTakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Batch version of fillOrKill. Allows a taker to specify a batch of orders that will either be atomically + * filled (each to the specified fillAmount) or aborted. + * @param orderFillRequests An array of objects that conform to the OrderFillRequest interface. + * @param takerAddress The user Ethereum address who would like to fill there orders. + * Must be available via the supplied Provider passed to 0x.js. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchFillOrKillAsync( + orderFillRequests: OrderFillRequest[], + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); + const exchangeContractAddresses = _.map( + orderFillRequests, + orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, + ); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + if (_.isEmpty(orderFillRequests)) { + throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); + } + const exchangeInstance = await this._getExchangeContractAsync(); + + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + for (const orderFillRequest of orderFillRequests) { + await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + orderFillRequest.signedOrder, + orderFillRequest.takerTokenFillAmount, + normalizedTakerAddress, + zrxTokenAddress, + ); + } + } + + const orderAddressesValuesAndTakerTokenFillAmounts = _.map(orderFillRequests, request => { + return [ + ...formatters.getOrderAddressesAndValues(request.signedOrder), + request.takerTokenFillAmount, + request.signedOrder.ecSignature.v, + request.signedOrder.ecSignature.r, + request.signedOrder.ecSignature.s, + ]; + }); + + // We use _.unzip because _.unzip doesn't type check if values have different types :'( + const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip( + orderAddressesValuesAndTakerTokenFillAmounts, + ); + const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + vParams, + rParams, + sParams, + { + from: normalizedTakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Cancel a given fill amount of an order. Cancellations are cumulative. + * @param order An object that conforms to the Order or SignedOrder interface. + * The order you would like to cancel. + * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel. + * @param transactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async cancelOrderAsync( + order: Order | SignedOrder, + cancelTakerTokenAmount: BigNumber, + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema('order', order, schemas.orderSchema); + assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount); + await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper); + const normalizedMakerAddress = order.maker.toLowerCase(); + + const exchangeInstance = await this._getExchangeContractAsync(); + + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + const orderHash = getOrderHashHex(order); + const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils.validateCancelOrderThrowIfInvalid( + order, + cancelTakerTokenAmount, + unavailableTakerTokenAmount, + ); + } + + const [orderAddresses, orderValues] = formatters.getOrderAddressesAndValues(order); + const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync( + orderAddresses, + orderValues, + cancelTakerTokenAmount, + { + from: normalizedMakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction. + * All orders must be from the same maker. + * @param orderCancellationRequests An array of objects that conform to the OrderCancellationRequest + * interface. + * @param transactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchCancelOrdersAsync( + orderCancellationRequests: OrderCancellationRequest[], + orderTransactionOpts: OrderTransactionOpts = {}, + ): Promise { + assert.doesConformToSchema( + 'orderCancellationRequests', + orderCancellationRequests, + schemas.orderCancellationRequestsSchema, + ); + const exchangeContractAddresses = _.map( + orderCancellationRequests, + orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress, + ); + assert.hasAtMostOneUniqueValue( + exchangeContractAddresses, + ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress, + ); + const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker); + assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed); + const maker = makers[0]; + await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper); + const normalizedMakerAddress = maker.toLowerCase(); + + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) + ? SHOULD_VALIDATE_BY_DEFAULT + : orderTransactionOpts.shouldValidate; + if (shouldValidate) { + for (const orderCancellationRequest of orderCancellationRequests) { + const orderHash = getOrderHashHex(orderCancellationRequest.order); + const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils.validateCancelOrderThrowIfInvalid( + orderCancellationRequest.order, + orderCancellationRequest.takerTokenCancelAmount, + unavailableTakerTokenAmount, + ); + } + } + if (_.isEmpty(orderCancellationRequests)) { + throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); + } + const exchangeInstance = await this._getExchangeContractAsync(); + const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(orderCancellationRequests, cancellationRequest => { + return [ + ...formatters.getOrderAddressesAndValues(cancellationRequest.order), + cancellationRequest.takerTokenCancelAmount, + ]; + }); + // We use _.unzip because _.unzip doesn't type check if values have different types :'( + const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip( + orderAddressesValuesAndTakerTokenCancelAmounts, + ); + const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync( + orderAddresses, + orderValues, + cancelTakerTokenAmounts, + { + from: normalizedMakerAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Subscribe to an event type emitted by the Exchange contract. + * @param eventName The exchange contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ExchangeEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const exchangeContractAddress = this.getContractAddress(); + const subscriptionToken = this._subscribe( + exchangeContractAddress, + eventName, + indexFilterValues, + artifacts.Exchange.abi, + callback, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super._unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The exchange contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ExchangeEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const exchangeContractAddress = this.getContractAddress(); + const logs = await this._getLogsAsync( + exchangeContractAddress, + eventName, + blockRange, + indexFilterValues, + artifacts.Exchange.abi, + ); + return logs; + } + /** + * Retrieves the Ethereum address of the Exchange contract deployed on the network + * that the user-passed web3 provider is connected to. + * @returns The Ethereum address of the Exchange contract being used. + */ + public getContractAddress(): string { + const contractAddress = this._getContractAddress(artifacts.Exchange, this._contractAddressIfExists); + return contractAddress; + } + /** + * Checks if order is still fillable and throws an error otherwise. Useful for orderbook + * pruning where you want to remove stale orders without knowing who the taker will be. + * @param signedOrder An object that conforms to the SignedOrder interface. The + * signedOrder you wish to validate. + * @param opts An object that conforms to the ValidateOrderFillableOpts + * interface. Allows specifying a specific fillTakerTokenAmount + * to validate for. + */ + public async validateOrderFillableOrThrowAsync( + signedOrder: SignedOrder, + opts?: ValidateOrderFillableOpts, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + const zrxTokenAddress = this.getZRXTokenAddress(); + const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined; + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + await this._orderValidationUtils.validateOrderFillableOrThrowAsync( + exchangeTradeEmulator, + signedOrder, + zrxTokenAddress, + expectedFillTakerTokenAmount, + ); + } + /** + * Checks if order fill will succeed and throws an error otherwise. + * @param signedOrder An object that conforms to the SignedOrder interface. The + * signedOrder you wish to fill. + * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill. + * @param takerAddress The user Ethereum address who would like to fill this order. + * Must be available via the supplied Provider passed to 0x.js. + */ + public async validateFillOrderThrowIfInvalidAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + normalizedTakerAddress, + zrxTokenAddress, + ); + } + /** + * Checks if cancelling a given order will succeed and throws an informative error if it won't. + * @param order An object that conforms to the Order or SignedOrder interface. + * The order you would like to cancel. + * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel. + */ + public async validateCancelOrderThrowIfInvalidAsync( + order: Order, + cancelTakerTokenAmount: BigNumber, + ): Promise { + assert.doesConformToSchema('order', order, schemas.orderSchema); + assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount); + const orderHash = getOrderHashHex(order); + const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils.validateCancelOrderThrowIfInvalid( + order, + cancelTakerTokenAmount, + unavailableTakerTokenAmount, + ); + } + /** + * Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't. + * @param signedOrder An object that conforms to the SignedOrder interface. The + * signedOrder you wish to fill. + * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill. + * @param takerAddress The user Ethereum address who would like to fill this order. + * Must be available via the supplied Provider passed to 0x.js. + */ + public async validateFillOrKillOrderThrowIfInvalidAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const normalizedTakerAddress = takerAddress.toLowerCase(); + const zrxTokenAddress = this.getZRXTokenAddress(); + const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); + await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + normalizedTakerAddress, + zrxTokenAddress, + ); + } + /** + * Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing: + * `(fillTakerTokenAmount * makerTokenAmount) / takerTokenAmount`. + * 0x Protocol does not accept any trades that result in large rounding errors. This means that tokens with few or + * no decimals can only be filled in quantities and ratios that avoid large rounding errors. + * @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that you wish to fill. + * @param takerTokenAmount The order size on the taker side + * @param makerTokenAmount The order size on the maker side + */ + public async isRoundingErrorAsync( + fillTakerTokenAmount: BigNumber, + takerTokenAmount: BigNumber, + makerTokenAmount: BigNumber, + ): Promise { + assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount); + assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount); + assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount); + const exchangeInstance = await this._getExchangeContractAsync(); + const isRoundingError = await exchangeInstance.isRoundingError.callAsync( + fillTakerTokenAmount, + takerTokenAmount, + makerTokenAmount, + ); + return isRoundingError; + } + /** + * Checks if logs contain LogError, which is emitted by Exchange contract on transaction failure. + * @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync` + */ + public throwLogErrorsAsErrors(logs: Array | LogEntry>): void { + const errLog = _.find(logs, { + event: ExchangeEvents.LogError, + }); + if (!_.isUndefined(errLog)) { + const logArgs = (errLog as LogWithDecodedArgs).args; + const errCode = logArgs.errorId; + const errMessage = this._exchangeContractErrCodesToMsg[errCode]; + throw new Error(errMessage); + } + } + /** + * Gets the latest OrderState of a signedOrder + * @param signedOrder The signedOrder + * @param stateLayer Optional, desired blockchain state layer (defaults to latest). + * @return OrderState of the signedOrder + */ + public async getOrderStateAsync( + signedOrder: SignedOrder, + stateLayer: BlockParamLiteral = BlockParamLiteral.Latest, + ): Promise { + const simpleBalanceAndProxyAllowanceFetcher = new SimpleBalanceAndProxyAllowanceFetcher( + this._tokenWrapper, + stateLayer, + ); + const simpleOrderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(this, stateLayer); + const orderStateUtils = new OrderStateUtils( + simpleBalanceAndProxyAllowanceFetcher, + simpleOrderFilledCancelledFetcher, + ); + const orderState = orderStateUtils.getOrderStateAsync(signedOrder); + return orderState; + } + /** + * Returns the ZRX token address used by the exchange contract. + * @return Address of ZRX token + */ + public getZRXTokenAddress(): string { + const contractAddress = this._getContractAddress(artifacts.ZRX, this._zrxContractAddressIfExists); + return contractAddress; + } + private _invalidateContractInstances(): void { + this.unsubscribeAll(); + delete this._exchangeContractIfExists; + } + private async _isValidSignatureUsingContractCallAsync( + dataHex: string, + ecSignature: ECSignature, + signerAddressHex: string, + ): Promise { + assert.isHexString('dataHex', dataHex); + assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema); + assert.isETHAddressHex('signerAddressHex', signerAddressHex); + const normalizedSignerAddress = signerAddressHex.toLowerCase(); + + const exchangeInstance = await this._getExchangeContractAsync(); + + const isValidSignature = await exchangeInstance.isValidSignature.callAsync( + normalizedSignerAddress, + dataHex, + ecSignature.v, + ecSignature.r, + ecSignature.s, + ); + return isValidSignature; + } + private async _getOrderHashHexUsingContractCallAsync(order: Order | SignedOrder): Promise { + const exchangeInstance = await this._getExchangeContractAsync(); + const [orderAddresses, orderValues] = formatters.getOrderAddressesAndValues(order); + const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues); + return orderHashHex; + } + private async _getExchangeContractAsync(): Promise { + if (!_.isUndefined(this._exchangeContractIfExists)) { + return this._exchangeContractIfExists; + } + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( + artifacts.Exchange, + this._contractAddressIfExists, + ); + const contractInstance = new ExchangeContract( + abi, + address, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + this._exchangeContractIfExists = contractInstance; + return this._exchangeContractIfExists; + } + private async _getTokenTransferProxyAddressAsync(): Promise { + const exchangeInstance = await this._getExchangeContractAsync(); + const tokenTransferProxyAddress = await exchangeInstance.TOKEN_TRANSFER_PROXY_CONTRACT.callAsync(); + const tokenTransferProxyAddressLowerCase = tokenTransferProxyAddress.toLowerCase(); + return tokenTransferProxyAddressLowerCase; + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/generated/dummy_token.ts b/packages/contract-wrappers/src/contract_wrappers/generated/dummy_token.ts new file mode 100644 index 000000000..ca923c7c5 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/generated/dummy_token.ts @@ -0,0 +1,84 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates. + */ +// tslint:disable:no-consecutive-blank-lines +// tslint:disable-next-line:no-unused-variable +import { BaseContract } from '@0xproject/base-contract'; +import { + BlockParam, + BlockParamLiteral, + CallData, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethers from 'ethers'; +import * as _ from 'lodash'; + +// tslint:disable:no-parameter-reassignment +export class DummyTokenContract extends BaseContract { + public setBalance = { + async sendTransactionAsync(_target: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as DummyTokenContract; + const inputAbi = self._lookupAbi('setBalance(address,uint256)').inputs; + [_target, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_target, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('setBalance(address,uint256)') + .functions.setBalance(_target, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.setBalance.estimateGasAsync.bind(self, _target, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_target: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as DummyTokenContract; + const inputAbi = self._lookupAbi('setBalance(address,uint256)').inputs; + [_target, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_target, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('setBalance(address,uint256)') + .functions.setBalance(_target, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_target: string, _value: BigNumber): string { + const self = (this as any) as DummyTokenContract; + const inputAbi = self._lookupAbi('setBalance(address,uint256)').inputs; + [_target, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_target, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('setBalance(address,uint256)') + .functions.setBalance(_target, _value).data; + return abiEncodedTransactionData; + }, + }; + constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial) { + super(abi, address, provider, defaults); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/generated/ether_token.ts b/packages/contract-wrappers/src/contract_wrappers/generated/ether_token.ts new file mode 100644 index 000000000..df95ba937 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/generated/ether_token.ts @@ -0,0 +1,621 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates. + */ +// tslint:disable:no-consecutive-blank-lines +// tslint:disable-next-line:no-unused-variable +import { BaseContract } from '@0xproject/base-contract'; +import { + BlockParam, + BlockParamLiteral, + CallData, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethers from 'ethers'; +import * as _ from 'lodash'; + +export type EtherTokenContractEventArgs = + | TransferContractEventArgs + | ApprovalContractEventArgs + | DepositContractEventArgs + | WithdrawalContractEventArgs; + +export enum EtherTokenEvents { + Transfer = 'Transfer', + Approval = 'Approval', + Deposit = 'Deposit', + Withdrawal = 'Withdrawal', +} + +export interface TransferContractEventArgs { + _from: string; + _to: string; + _value: BigNumber; +} + +export interface ApprovalContractEventArgs { + _owner: string; + _spender: string; + _value: BigNumber; +} + +export interface DepositContractEventArgs { + _owner: string; + _value: BigNumber; +} + +export interface WithdrawalContractEventArgs { + _owner: string; + _value: BigNumber; +} + +// tslint:disable:no-parameter-reassignment +export class EtherTokenContract extends BaseContract { + public name = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'name()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.name() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'name' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public approve = { + async sendTransactionAsync(_spender: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('approve(address,uint256)').inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('approve(address,uint256)') + .functions.approve(_spender, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.approve.estimateGasAsync.bind(self, _spender, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_spender: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('approve(address,uint256)').inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('approve(address,uint256)') + .functions.approve(_spender, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_spender: string, _value: BigNumber): string { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('approve(address,uint256)').inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('approve(address,uint256)') + .functions.approve(_spender, _value).data; + return abiEncodedTransactionData; + }, + async callAsync( + _spender: string, + _value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'approve(address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.approve(_spender, _value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'approve' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public totalSupply = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'totalSupply()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.totalSupply() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'totalSupply' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public transferFrom = { + async sendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,uint256)').inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('transferFrom(address,address,uint256)') + .functions.transferFrom(_from, _to, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transferFrom.estimateGasAsync.bind(self, _from, _to, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,uint256)').inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('transferFrom(address,address,uint256)') + .functions.transferFrom(_from, _to, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_from: string, _to: string, _value: BigNumber): string { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,uint256)').inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transferFrom(address,address,uint256)') + .functions.transferFrom(_from, _to, _value).data; + return abiEncodedTransactionData; + }, + async callAsync( + _from: string, + _to: string, + _value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'transferFrom(address,address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.transferFrom(_from, _to, _value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'transferFrom' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public withdraw = { + async sendTransactionAsync(amount: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('withdraw(uint256)').inputs; + [amount] = BaseContract._formatABIDataItemList( + inputAbi, + [amount], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self._lookupEthersInterface('withdraw(uint256)').functions.withdraw(amount).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.withdraw.estimateGasAsync.bind(self, amount), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(amount: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('withdraw(uint256)').inputs; + [amount] = BaseContract._formatABIDataItemList( + inputAbi, + [amount], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self._lookupEthersInterface('withdraw(uint256)').functions.withdraw(amount).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(amount: BigNumber): string { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('withdraw(uint256)').inputs; + [amount] = BaseContract._formatABIDataItemList( + inputAbi, + [amount], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('withdraw(uint256)') + .functions.withdraw(amount).data; + return abiEncodedTransactionData; + }, + }; + public decimals = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'decimals()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.decimals() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'decimals' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public balanceOf = { + async callAsync( + _owner: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'balanceOf(address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_owner] = BaseContract._formatABIDataItemList( + inputAbi, + [_owner], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.balanceOf(_owner) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'balanceOf' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public symbol = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'symbol()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.symbol() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'symbol' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public transfer = { + async sendTransactionAsync(_to: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('transfer(address,uint256)').inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self._lookupEthersInterface('transfer(address,uint256)').functions.transfer(_to, _value) + .data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transfer.estimateGasAsync.bind(self, _to, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_to: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('transfer(address,uint256)').inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self._lookupEthersInterface('transfer(address,uint256)').functions.transfer(_to, _value) + .data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_to: string, _value: BigNumber): string { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('transfer(address,uint256)').inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transfer(address,uint256)') + .functions.transfer(_to, _value).data; + return abiEncodedTransactionData; + }, + async callAsync( + _to: string, + _value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'transfer(address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.transfer(_to, _value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'transfer' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public deposit = { + async sendTransactionAsync(txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('deposit()').inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const encodedData = self._lookupEthersInterface('deposit()').functions.deposit().data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.deposit.estimateGasAsync.bind(self), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(txData: Partial = {}): Promise { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('deposit()').inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(this)); + const encodedData = self._lookupEthersInterface('deposit()').functions.deposit().data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(): string { + const self = (this as any) as EtherTokenContract; + const inputAbi = self._lookupAbi('deposit()').inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const abiEncodedTransactionData = self._lookupEthersInterface('deposit()').functions.deposit().data; + return abiEncodedTransactionData; + }, + }; + public allowance = { + async callAsync( + _owner: string, + _spender: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as EtherTokenContract; + const functionSignature = 'allowance(address,address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_owner, _spender] = BaseContract._formatABIDataItemList( + inputAbi, + [_owner, _spender], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.allowance(_owner, _spender) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'allowance' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial) { + super(abi, address, provider, defaults); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/generated/exchange.ts b/packages/contract-wrappers/src/contract_wrappers/generated/exchange.ts new file mode 100644 index 000000000..da2fc1754 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/generated/exchange.ts @@ -0,0 +1,1459 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates. + */ +// tslint:disable:no-consecutive-blank-lines +// tslint:disable-next-line:no-unused-variable +import { BaseContract } from '@0xproject/base-contract'; +import { + BlockParam, + BlockParamLiteral, + CallData, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethers from 'ethers'; +import * as _ from 'lodash'; + +export type ExchangeContractEventArgs = + | LogFillContractEventArgs + | LogCancelContractEventArgs + | LogErrorContractEventArgs; + +export enum ExchangeEvents { + LogFill = 'LogFill', + LogCancel = 'LogCancel', + LogError = 'LogError', +} + +export interface LogFillContractEventArgs { + maker: string; + taker: string; + feeRecipient: string; + makerToken: string; + takerToken: string; + filledMakerTokenAmount: BigNumber; + filledTakerTokenAmount: BigNumber; + paidMakerFee: BigNumber; + paidTakerFee: BigNumber; + tokens: string; + orderHash: string; +} + +export interface LogCancelContractEventArgs { + maker: string; + feeRecipient: string; + makerToken: string; + takerToken: string; + cancelledMakerTokenAmount: BigNumber; + cancelledTakerTokenAmount: BigNumber; + tokens: string; + orderHash: string; +} + +export interface LogErrorContractEventArgs { + errorId: number; + orderHash: string; +} + +// tslint:disable:no-parameter-reassignment +export class ExchangeContract extends BaseContract { + public isRoundingError = { + async callAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'isRoundingError(uint256,uint256,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [numerator, denominator, target] = BaseContract._formatABIDataItemList( + inputAbi, + [numerator, denominator, target], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.isRoundingError(numerator, denominator, target) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'isRoundingError' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public filled = { + async callAsync( + index_0: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'filled(bytes32)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [index_0] = BaseContract._formatABIDataItemList( + inputAbi, + [index_0], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.filled(index_0) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'filled' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public cancelled = { + async callAsync( + index_0: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'cancelled(bytes32)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [index_0] = BaseContract._formatABIDataItemList( + inputAbi, + [index_0], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.cancelled(index_0) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'cancelled' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public fillOrdersUpTo = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])', + ).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface( + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])', + ) + .functions.fillOrdersUpTo( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.fillOrdersUpTo.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])', + ).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface( + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])', + ) + .functions.fillOrdersUpTo( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])', + ).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface( + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])', + ) + .functions.fillOrdersUpTo( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + return abiEncodedTransactionData; + }, + async callAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = + 'fillOrdersUpTo(address[5][],uint256[6][],uint256,bool,uint8[],bytes32[],bytes32[])'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.fillOrdersUpTo( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'fillOrdersUpTo' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public cancelOrder = { + async sendTransactionAsync( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('cancelOrder(address[5],uint256[6],uint256)').inputs; + [orderAddresses, orderValues, cancelTakerTokenAmount] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmount], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('cancelOrder(address[5],uint256[6],uint256)') + .functions.cancelOrder(orderAddresses, orderValues, cancelTakerTokenAmount).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.cancelOrder.estimateGasAsync.bind(self, orderAddresses, orderValues, cancelTakerTokenAmount), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('cancelOrder(address[5],uint256[6],uint256)').inputs; + [orderAddresses, orderValues, cancelTakerTokenAmount] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmount], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('cancelOrder(address[5],uint256[6],uint256)') + .functions.cancelOrder(orderAddresses, orderValues, cancelTakerTokenAmount).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('cancelOrder(address[5],uint256[6],uint256)').inputs; + [orderAddresses, orderValues, cancelTakerTokenAmount] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmount], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('cancelOrder(address[5],uint256[6],uint256)') + .functions.cancelOrder(orderAddresses, orderValues, cancelTakerTokenAmount).data; + return abiEncodedTransactionData; + }, + async callAsync( + orderAddresses: string[], + orderValues: BigNumber[], + cancelTakerTokenAmount: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'cancelOrder(address[5],uint256[6],uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [orderAddresses, orderValues, cancelTakerTokenAmount] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmount], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.cancelOrder(orderAddresses, orderValues, cancelTakerTokenAmount) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'cancelOrder' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public ZRX_TOKEN_CONTRACT = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'ZRX_TOKEN_CONTRACT()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.ZRX_TOKEN_CONTRACT() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'ZRX_TOKEN_CONTRACT' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public batchFillOrKillOrders = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + v: Array, + r: string[], + s: string[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'batchFillOrKillOrders(address[5][],uint256[6][],uint256[],uint8[],bytes32[],bytes32[])', + ).inputs; + [orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface( + 'batchFillOrKillOrders(address[5][],uint256[6][],uint256[],uint8[],bytes32[],bytes32[])', + ) + .functions.batchFillOrKillOrders(orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.batchFillOrKillOrders.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmounts, + v, + r, + s, + ), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + v: Array, + r: string[], + s: string[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'batchFillOrKillOrders(address[5][],uint256[6][],uint256[],uint8[],bytes32[],bytes32[])', + ).inputs; + [orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface( + 'batchFillOrKillOrders(address[5][],uint256[6][],uint256[],uint8[],bytes32[],bytes32[])', + ) + .functions.batchFillOrKillOrders(orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + v: Array, + r: string[], + s: string[], + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'batchFillOrKillOrders(address[5][],uint256[6][],uint256[],uint8[],bytes32[],bytes32[])', + ).inputs; + [orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface( + 'batchFillOrKillOrders(address[5][],uint256[6][],uint256[],uint8[],bytes32[],bytes32[])', + ) + .functions.batchFillOrKillOrders(orderAddresses, orderValues, fillTakerTokenAmounts, v, r, s).data; + return abiEncodedTransactionData; + }, + }; + public fillOrKillOrder = { + async sendTransactionAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + v: number | BigNumber, + r: string, + s: string, + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('fillOrKillOrder(address[5],uint256[6],uint256,uint8,bytes32,bytes32)') + .inputs; + [orderAddresses, orderValues, fillTakerTokenAmount, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, fillTakerTokenAmount, v, r, s], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('fillOrKillOrder(address[5],uint256[6],uint256,uint8,bytes32,bytes32)') + .functions.fillOrKillOrder(orderAddresses, orderValues, fillTakerTokenAmount, v, r, s).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.fillOrKillOrder.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmount, + v, + r, + s, + ), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + v: number | BigNumber, + r: string, + s: string, + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('fillOrKillOrder(address[5],uint256[6],uint256,uint8,bytes32,bytes32)') + .inputs; + [orderAddresses, orderValues, fillTakerTokenAmount, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, fillTakerTokenAmount, v, r, s], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('fillOrKillOrder(address[5],uint256[6],uint256,uint8,bytes32,bytes32)') + .functions.fillOrKillOrder(orderAddresses, orderValues, fillTakerTokenAmount, v, r, s).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + v: number | BigNumber, + r: string, + s: string, + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('fillOrKillOrder(address[5],uint256[6],uint256,uint8,bytes32,bytes32)') + .inputs; + [orderAddresses, orderValues, fillTakerTokenAmount, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, fillTakerTokenAmount, v, r, s], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('fillOrKillOrder(address[5],uint256[6],uint256,uint8,bytes32,bytes32)') + .functions.fillOrKillOrder(orderAddresses, orderValues, fillTakerTokenAmount, v, r, s).data; + return abiEncodedTransactionData; + }, + }; + public getUnavailableTakerTokenAmount = { + async callAsync( + orderHash: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'getUnavailableTakerTokenAmount(bytes32)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [orderHash] = BaseContract._formatABIDataItemList( + inputAbi, + [orderHash], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getUnavailableTakerTokenAmount(orderHash) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getUnavailableTakerTokenAmount' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public isValidSignature = { + async callAsync( + signer: string, + hash: string, + v: number | BigNumber, + r: string, + s: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'isValidSignature(address,bytes32,uint8,bytes32,bytes32)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [signer, hash, v, r, s] = BaseContract._formatABIDataItemList( + inputAbi, + [signer, hash, v, r, s], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.isValidSignature(signer, hash, v, r, s) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'isValidSignature' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public getPartialAmount = { + async callAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'getPartialAmount(uint256,uint256,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [numerator, denominator, target] = BaseContract._formatABIDataItemList( + inputAbi, + [numerator, denominator, target], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getPartialAmount(numerator, denominator, target) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getPartialAmount' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public TOKEN_TRANSFER_PROXY_CONTRACT = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'TOKEN_TRANSFER_PROXY_CONTRACT()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.TOKEN_TRANSFER_PROXY_CONTRACT() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'TOKEN_TRANSFER_PROXY_CONTRACT' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public batchFillOrders = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'batchFillOrders(address[5][],uint256[6][],uint256[],bool,uint8[],bytes32[],bytes32[])', + ).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface( + 'batchFillOrders(address[5][],uint256[6][],uint256[],bool,uint8[],bytes32[],bytes32[])', + ) + .functions.batchFillOrders( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.batchFillOrders.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'batchFillOrders(address[5][],uint256[6][],uint256[],bool,uint8[],bytes32[],bytes32[])', + ).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface( + 'batchFillOrders(address[5][],uint256[6][],uint256[],bool,uint8[],bytes32[],bytes32[])', + ) + .functions.batchFillOrders( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + fillTakerTokenAmounts: BigNumber[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: Array, + r: string[], + s: string[], + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi( + 'batchFillOrders(address[5][],uint256[6][],uint256[],bool,uint8[],bytes32[],bytes32[])', + ).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface( + 'batchFillOrders(address[5][],uint256[6][],uint256[],bool,uint8[],bytes32[],bytes32[])', + ) + .functions.batchFillOrders( + orderAddresses, + orderValues, + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + return abiEncodedTransactionData; + }, + }; + public batchCancelOrders = { + async sendTransactionAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + cancelTakerTokenAmounts: BigNumber[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('batchCancelOrders(address[5][],uint256[6][],uint256[])').inputs; + [orderAddresses, orderValues, cancelTakerTokenAmounts] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmounts], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('batchCancelOrders(address[5][],uint256[6][],uint256[])') + .functions.batchCancelOrders(orderAddresses, orderValues, cancelTakerTokenAmounts).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.batchCancelOrders.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + cancelTakerTokenAmounts, + ), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[][], + orderValues: BigNumber[][], + cancelTakerTokenAmounts: BigNumber[], + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('batchCancelOrders(address[5][],uint256[6][],uint256[])').inputs; + [orderAddresses, orderValues, cancelTakerTokenAmounts] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmounts], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('batchCancelOrders(address[5][],uint256[6][],uint256[])') + .functions.batchCancelOrders(orderAddresses, orderValues, cancelTakerTokenAmounts).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[][], + orderValues: BigNumber[][], + cancelTakerTokenAmounts: BigNumber[], + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('batchCancelOrders(address[5][],uint256[6][],uint256[])').inputs; + [orderAddresses, orderValues, cancelTakerTokenAmounts] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues, cancelTakerTokenAmounts], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('batchCancelOrders(address[5][],uint256[6][],uint256[])') + .functions.batchCancelOrders(orderAddresses, orderValues, cancelTakerTokenAmounts).data; + return abiEncodedTransactionData; + }, + }; + public fillOrder = { + async sendTransactionAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number | BigNumber, + r: string, + s: string, + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)') + .inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)') + .functions.fillOrder( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.fillOrder.estimateGasAsync.bind( + self, + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number | BigNumber, + r: string, + s: string, + txData: Partial = {}, + ): Promise { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)') + .inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)') + .functions.fillOrder( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number | BigNumber, + r: string, + s: string, + ): string { + const self = (this as any) as ExchangeContract; + const inputAbi = self._lookupAbi('fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)') + .inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)') + .functions.fillOrder( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ).data; + return abiEncodedTransactionData; + }, + async callAsync( + orderAddresses: string[], + orderValues: BigNumber[], + fillTakerTokenAmount: BigNumber, + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + v: number | BigNumber, + r: string, + s: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'fillOrder(address[5],uint256[6],uint256,bool,uint8,bytes32,bytes32)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ] = BaseContract._formatABIDataItemList( + inputAbi, + [ + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.fillOrder( + orderAddresses, + orderValues, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v, + r, + s, + ) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'fillOrder' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public getOrderHash = { + async callAsync( + orderAddresses: string[], + orderValues: BigNumber[], + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'getOrderHash(address[5],uint256[6])'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [orderAddresses, orderValues] = BaseContract._formatABIDataItemList( + inputAbi, + [orderAddresses, orderValues], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getOrderHash(orderAddresses, orderValues) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getOrderHash' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public EXTERNAL_QUERY_GAS_LIMIT = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'EXTERNAL_QUERY_GAS_LIMIT()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.EXTERNAL_QUERY_GAS_LIMIT() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'EXTERNAL_QUERY_GAS_LIMIT' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public VERSION = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as ExchangeContract; + const functionSignature = 'VERSION()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.VERSION() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'VERSION' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial) { + super(abi, address, provider, defaults); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/generated/token.ts b/packages/contract-wrappers/src/contract_wrappers/generated/token.ts new file mode 100644 index 000000000..130265d4d --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/generated/token.ts @@ -0,0 +1,432 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates. + */ +// tslint:disable:no-consecutive-blank-lines +// tslint:disable-next-line:no-unused-variable +import { BaseContract } from '@0xproject/base-contract'; +import { + BlockParam, + BlockParamLiteral, + CallData, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethers from 'ethers'; +import * as _ from 'lodash'; + +export type TokenContractEventArgs = TransferContractEventArgs | ApprovalContractEventArgs; + +export enum TokenEvents { + Transfer = 'Transfer', + Approval = 'Approval', +} + +export interface TransferContractEventArgs { + _from: string; + _to: string; + _value: BigNumber; +} + +export interface ApprovalContractEventArgs { + _owner: string; + _spender: string; + _value: BigNumber; +} + +// tslint:disable:no-parameter-reassignment +export class TokenContract extends BaseContract { + public approve = { + async sendTransactionAsync(_spender: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('approve(address,uint256)').inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('approve(address,uint256)') + .functions.approve(_spender, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.approve.estimateGasAsync.bind(self, _spender, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_spender: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('approve(address,uint256)').inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('approve(address,uint256)') + .functions.approve(_spender, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_spender: string, _value: BigNumber): string { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('approve(address,uint256)').inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('approve(address,uint256)') + .functions.approve(_spender, _value).data; + return abiEncodedTransactionData; + }, + async callAsync( + _spender: string, + _value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenContract; + const functionSignature = 'approve(address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_spender, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_spender, _value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.approve(_spender, _value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'approve' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public totalSupply = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenContract; + const functionSignature = 'totalSupply()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.totalSupply() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'totalSupply' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public transferFrom = { + async sendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,uint256)').inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('transferFrom(address,address,uint256)') + .functions.transferFrom(_from, _to, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transferFrom.estimateGasAsync.bind(self, _from, _to, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + _from: string, + _to: string, + _value: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,uint256)').inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('transferFrom(address,address,uint256)') + .functions.transferFrom(_from, _to, _value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_from: string, _to: string, _value: BigNumber): string { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,uint256)').inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transferFrom(address,address,uint256)') + .functions.transferFrom(_from, _to, _value).data; + return abiEncodedTransactionData; + }, + async callAsync( + _from: string, + _to: string, + _value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenContract; + const functionSignature = 'transferFrom(address,address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_from, _to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_from, _to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.transferFrom(_from, _to, _value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'transferFrom' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public balanceOf = { + async callAsync( + _owner: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenContract; + const functionSignature = 'balanceOf(address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_owner] = BaseContract._formatABIDataItemList( + inputAbi, + [_owner], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.balanceOf(_owner) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'balanceOf' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public transfer = { + async sendTransactionAsync(_to: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('transfer(address,uint256)').inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self._lookupEthersInterface('transfer(address,uint256)').functions.transfer(_to, _value) + .data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transfer.estimateGasAsync.bind(self, _to, _value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_to: string, _value: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('transfer(address,uint256)').inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self._lookupEthersInterface('transfer(address,uint256)').functions.transfer(_to, _value) + .data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_to: string, _value: BigNumber): string { + const self = (this as any) as TokenContract; + const inputAbi = self._lookupAbi('transfer(address,uint256)').inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transfer(address,uint256)') + .functions.transfer(_to, _value).data; + return abiEncodedTransactionData; + }, + async callAsync( + _to: string, + _value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenContract; + const functionSignature = 'transfer(address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_to, _value] = BaseContract._formatABIDataItemList( + inputAbi, + [_to, _value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.transfer(_to, _value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'transfer' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public allowance = { + async callAsync( + _owner: string, + _spender: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenContract; + const functionSignature = 'allowance(address,address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_owner, _spender] = BaseContract._formatABIDataItemList( + inputAbi, + [_owner, _spender], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.allowance(_owner, _spender) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'allowance' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial) { + super(abi, address, provider, defaults); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/generated/token_registry.ts b/packages/contract-wrappers/src/contract_wrappers/generated/token_registry.ts new file mode 100644 index 000000000..243f81088 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/generated/token_registry.ts @@ -0,0 +1,799 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates. + */ +// tslint:disable:no-consecutive-blank-lines +// tslint:disable-next-line:no-unused-variable +import { BaseContract } from '@0xproject/base-contract'; +import { + BlockParam, + BlockParamLiteral, + CallData, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethers from 'ethers'; +import * as _ from 'lodash'; + +export type TokenRegistryContractEventArgs = + | LogAddTokenContractEventArgs + | LogRemoveTokenContractEventArgs + | LogTokenNameChangeContractEventArgs + | LogTokenSymbolChangeContractEventArgs + | LogTokenIpfsHashChangeContractEventArgs + | LogTokenSwarmHashChangeContractEventArgs; + +export enum TokenRegistryEvents { + LogAddToken = 'LogAddToken', + LogRemoveToken = 'LogRemoveToken', + LogTokenNameChange = 'LogTokenNameChange', + LogTokenSymbolChange = 'LogTokenSymbolChange', + LogTokenIpfsHashChange = 'LogTokenIpfsHashChange', + LogTokenSwarmHashChange = 'LogTokenSwarmHashChange', +} + +export interface LogAddTokenContractEventArgs { + token: string; + name: string; + symbol: string; + decimals: number; + ipfsHash: string; + swarmHash: string; +} + +export interface LogRemoveTokenContractEventArgs { + token: string; + name: string; + symbol: string; + decimals: number; + ipfsHash: string; + swarmHash: string; +} + +export interface LogTokenNameChangeContractEventArgs { + token: string; + oldName: string; + newName: string; +} + +export interface LogTokenSymbolChangeContractEventArgs { + token: string; + oldSymbol: string; + newSymbol: string; +} + +export interface LogTokenIpfsHashChangeContractEventArgs { + token: string; + oldIpfsHash: string; + newIpfsHash: string; +} + +export interface LogTokenSwarmHashChangeContractEventArgs { + token: string; + oldSwarmHash: string; + newSwarmHash: string; +} + +// tslint:disable:no-parameter-reassignment +export class TokenRegistryContract extends BaseContract { + public removeToken = { + async sendTransactionAsync(_token: string, _index: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('removeToken(address,uint256)').inputs; + [_token, _index] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _index], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('removeToken(address,uint256)') + .functions.removeToken(_token, _index).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.removeToken.estimateGasAsync.bind(self, _token, _index), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_token: string, _index: BigNumber, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('removeToken(address,uint256)').inputs; + [_token, _index] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _index], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('removeToken(address,uint256)') + .functions.removeToken(_token, _index).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_token: string, _index: BigNumber): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('removeToken(address,uint256)').inputs; + [_token, _index] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _index], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('removeToken(address,uint256)') + .functions.removeToken(_token, _index).data; + return abiEncodedTransactionData; + }, + }; + public getTokenAddressByName = { + async callAsync(_name: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'getTokenAddressByName(string)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_name] = BaseContract._formatABIDataItemList( + inputAbi, + [_name], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getTokenAddressByName(_name) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getTokenAddressByName' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public getTokenAddressBySymbol = { + async callAsync(_symbol: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'getTokenAddressBySymbol(string)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_symbol] = BaseContract._formatABIDataItemList( + inputAbi, + [_symbol], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getTokenAddressBySymbol(_symbol) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getTokenAddressBySymbol' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public setTokenSwarmHash = { + async sendTransactionAsync(_token: string, _swarmHash: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenSwarmHash(address,bytes)').inputs; + [_token, _swarmHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _swarmHash], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('setTokenSwarmHash(address,bytes)') + .functions.setTokenSwarmHash(_token, _swarmHash).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.setTokenSwarmHash.estimateGasAsync.bind(self, _token, _swarmHash), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_token: string, _swarmHash: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenSwarmHash(address,bytes)').inputs; + [_token, _swarmHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _swarmHash], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('setTokenSwarmHash(address,bytes)') + .functions.setTokenSwarmHash(_token, _swarmHash).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_token: string, _swarmHash: string): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenSwarmHash(address,bytes)').inputs; + [_token, _swarmHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _swarmHash], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('setTokenSwarmHash(address,bytes)') + .functions.setTokenSwarmHash(_token, _swarmHash).data; + return abiEncodedTransactionData; + }, + }; + public getTokenMetaData = { + async callAsync( + _token: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[string, string, string, number, string, string]> { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'getTokenMetaData(address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_token] = BaseContract._formatABIDataItemList( + inputAbi, + [_token], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getTokenMetaData(_token) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getTokenMetaData' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray; + }, + }; + public owner = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'owner()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.owner() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'owner' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public addToken = { + async sendTransactionAsync( + _token: string, + _name: string, + _symbol: string, + _decimals: number | BigNumber, + _ipfsHash: string, + _swarmHash: string, + txData: Partial = {}, + ): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('addToken(address,string,string,uint8,bytes,bytes)').inputs; + [_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('addToken(address,string,string,uint8,bytes,bytes)') + .functions.addToken(_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.addToken.estimateGasAsync.bind(self, _token, _name, _symbol, _decimals, _ipfsHash, _swarmHash), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + _token: string, + _name: string, + _symbol: string, + _decimals: number | BigNumber, + _ipfsHash: string, + _swarmHash: string, + txData: Partial = {}, + ): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('addToken(address,string,string,uint8,bytes,bytes)').inputs; + [_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('addToken(address,string,string,uint8,bytes,bytes)') + .functions.addToken(_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData( + _token: string, + _name: string, + _symbol: string, + _decimals: number | BigNumber, + _ipfsHash: string, + _swarmHash: string, + ): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('addToken(address,string,string,uint8,bytes,bytes)').inputs; + [_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('addToken(address,string,string,uint8,bytes,bytes)') + .functions.addToken(_token, _name, _symbol, _decimals, _ipfsHash, _swarmHash).data; + return abiEncodedTransactionData; + }, + }; + public setTokenName = { + async sendTransactionAsync(_token: string, _name: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenName(address,string)').inputs; + [_token, _name] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _name], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('setTokenName(address,string)') + .functions.setTokenName(_token, _name).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.setTokenName.estimateGasAsync.bind(self, _token, _name), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_token: string, _name: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenName(address,string)').inputs; + [_token, _name] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _name], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('setTokenName(address,string)') + .functions.setTokenName(_token, _name).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_token: string, _name: string): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenName(address,string)').inputs; + [_token, _name] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _name], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('setTokenName(address,string)') + .functions.setTokenName(_token, _name).data; + return abiEncodedTransactionData; + }, + }; + public tokens = { + async callAsync( + index_0: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[string, string, string, number, string, string]> { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'tokens(address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [index_0] = BaseContract._formatABIDataItemList( + inputAbi, + [index_0], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.tokens(index_0) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'tokens' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray; + }, + }; + public tokenAddresses = { + async callAsync( + index_0: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'tokenAddresses(uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [index_0] = BaseContract._formatABIDataItemList( + inputAbi, + [index_0], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.tokenAddresses(index_0) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'tokenAddresses' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public getTokenByName = { + async callAsync( + _name: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[string, string, string, number, string, string]> { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'getTokenByName(string)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_name] = BaseContract._formatABIDataItemList( + inputAbi, + [_name], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getTokenByName(_name) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getTokenByName' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray; + }, + }; + public getTokenAddresses = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'getTokenAddresses()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getTokenAddresses() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getTokenAddresses' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public setTokenIpfsHash = { + async sendTransactionAsync(_token: string, _ipfsHash: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenIpfsHash(address,bytes)').inputs; + [_token, _ipfsHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _ipfsHash], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('setTokenIpfsHash(address,bytes)') + .functions.setTokenIpfsHash(_token, _ipfsHash).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.setTokenIpfsHash.estimateGasAsync.bind(self, _token, _ipfsHash), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_token: string, _ipfsHash: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenIpfsHash(address,bytes)').inputs; + [_token, _ipfsHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _ipfsHash], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('setTokenIpfsHash(address,bytes)') + .functions.setTokenIpfsHash(_token, _ipfsHash).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_token: string, _ipfsHash: string): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenIpfsHash(address,bytes)').inputs; + [_token, _ipfsHash] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _ipfsHash], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('setTokenIpfsHash(address,bytes)') + .functions.setTokenIpfsHash(_token, _ipfsHash).data; + return abiEncodedTransactionData; + }, + }; + public getTokenBySymbol = { + async callAsync( + _symbol: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[string, string, string, number, string, string]> { + const self = (this as any) as TokenRegistryContract; + const functionSignature = 'getTokenBySymbol(string)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [_symbol] = BaseContract._formatABIDataItemList( + inputAbi, + [_symbol], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getTokenBySymbol(_symbol) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getTokenBySymbol' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray; + }, + }; + public setTokenSymbol = { + async sendTransactionAsync(_token: string, _symbol: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenSymbol(address,string)').inputs; + [_token, _symbol] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _symbol], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('setTokenSymbol(address,string)') + .functions.setTokenSymbol(_token, _symbol).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.setTokenSymbol.estimateGasAsync.bind(self, _token, _symbol), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(_token: string, _symbol: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenSymbol(address,string)').inputs; + [_token, _symbol] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _symbol], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('setTokenSymbol(address,string)') + .functions.setTokenSymbol(_token, _symbol).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(_token: string, _symbol: string): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('setTokenSymbol(address,string)').inputs; + [_token, _symbol] = BaseContract._formatABIDataItemList( + inputAbi, + [_token, _symbol], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('setTokenSymbol(address,string)') + .functions.setTokenSymbol(_token, _symbol).data; + return abiEncodedTransactionData; + }, + }; + public transferOwnership = { + async sendTransactionAsync(newOwner: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('transferOwnership(address)').inputs; + [newOwner] = BaseContract._formatABIDataItemList( + inputAbi, + [newOwner], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('transferOwnership(address)') + .functions.transferOwnership(newOwner).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transferOwnership.estimateGasAsync.bind(self, newOwner), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(newOwner: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('transferOwnership(address)').inputs; + [newOwner] = BaseContract._formatABIDataItemList( + inputAbi, + [newOwner], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('transferOwnership(address)') + .functions.transferOwnership(newOwner).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(newOwner: string): string { + const self = (this as any) as TokenRegistryContract; + const inputAbi = self._lookupAbi('transferOwnership(address)').inputs; + [newOwner] = BaseContract._formatABIDataItemList( + inputAbi, + [newOwner], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transferOwnership(address)') + .functions.transferOwnership(newOwner).data; + return abiEncodedTransactionData; + }, + }; + constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial) { + super(abi, address, provider, defaults); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/generated/token_transfer_proxy.ts b/packages/contract-wrappers/src/contract_wrappers/generated/token_transfer_proxy.ts new file mode 100644 index 000000000..e533430ff --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/generated/token_transfer_proxy.ts @@ -0,0 +1,447 @@ +/** + * This file is auto-generated using abi-gen. Don't edit directly. + * Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates. + */ +// tslint:disable:no-consecutive-blank-lines +// tslint:disable-next-line:no-unused-variable +import { BaseContract } from '@0xproject/base-contract'; +import { + BlockParam, + BlockParamLiteral, + CallData, + ContractAbi, + DataItem, + MethodAbi, + Provider, + TxData, + TxDataPayable, +} from '@0xproject/types'; +import { BigNumber, classUtils, promisify } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as ethers from 'ethers'; +import * as _ from 'lodash'; + +export type TokenTransferProxyContractEventArgs = + | LogAuthorizedAddressAddedContractEventArgs + | LogAuthorizedAddressRemovedContractEventArgs; + +export enum TokenTransferProxyEvents { + LogAuthorizedAddressAdded = 'LogAuthorizedAddressAdded', + LogAuthorizedAddressRemoved = 'LogAuthorizedAddressRemoved', +} + +export interface LogAuthorizedAddressAddedContractEventArgs { + target: string; + caller: string; +} + +export interface LogAuthorizedAddressRemovedContractEventArgs { + target: string; + caller: string; +} + +// tslint:disable:no-parameter-reassignment +export class TokenTransferProxyContract extends BaseContract { + public transferFrom = { + async sendTransactionAsync( + token: string, + from: string, + to: string, + value: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,address,uint256)').inputs; + [token, from, to, value] = BaseContract._formatABIDataItemList( + inputAbi, + [token, from, to, value], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('transferFrom(address,address,address,uint256)') + .functions.transferFrom(token, from, to, value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transferFrom.estimateGasAsync.bind(self, token, from, to, value), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync( + token: string, + from: string, + to: string, + value: BigNumber, + txData: Partial = {}, + ): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,address,uint256)').inputs; + [token, from, to, value] = BaseContract._formatABIDataItemList( + inputAbi, + [token, from, to, value], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('transferFrom(address,address,address,uint256)') + .functions.transferFrom(token, from, to, value).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(token: string, from: string, to: string, value: BigNumber): string { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('transferFrom(address,address,address,uint256)').inputs; + [token, from, to, value] = BaseContract._formatABIDataItemList( + inputAbi, + [token, from, to, value], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transferFrom(address,address,address,uint256)') + .functions.transferFrom(token, from, to, value).data; + return abiEncodedTransactionData; + }, + async callAsync( + token: string, + from: string, + to: string, + value: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenTransferProxyContract; + const functionSignature = 'transferFrom(address,address,address,uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [token, from, to, value] = BaseContract._formatABIDataItemList( + inputAbi, + [token, from, to, value], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.transferFrom(token, from, to, value) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'transferFrom' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public addAuthorizedAddress = { + async sendTransactionAsync(target: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('addAuthorizedAddress(address)').inputs; + [target] = BaseContract._formatABIDataItemList( + inputAbi, + [target], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('addAuthorizedAddress(address)') + .functions.addAuthorizedAddress(target).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.addAuthorizedAddress.estimateGasAsync.bind(self, target), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(target: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('addAuthorizedAddress(address)').inputs; + [target] = BaseContract._formatABIDataItemList( + inputAbi, + [target], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('addAuthorizedAddress(address)') + .functions.addAuthorizedAddress(target).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(target: string): string { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('addAuthorizedAddress(address)').inputs; + [target] = BaseContract._formatABIDataItemList( + inputAbi, + [target], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('addAuthorizedAddress(address)') + .functions.addAuthorizedAddress(target).data; + return abiEncodedTransactionData; + }, + }; + public authorities = { + async callAsync( + index_0: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenTransferProxyContract; + const functionSignature = 'authorities(uint256)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [index_0] = BaseContract._formatABIDataItemList( + inputAbi, + [index_0], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.authorities(index_0) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'authorities' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public removeAuthorizedAddress = { + async sendTransactionAsync(target: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('removeAuthorizedAddress(address)').inputs; + [target] = BaseContract._formatABIDataItemList( + inputAbi, + [target], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('removeAuthorizedAddress(address)') + .functions.removeAuthorizedAddress(target).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.removeAuthorizedAddress.estimateGasAsync.bind(self, target), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(target: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('removeAuthorizedAddress(address)').inputs; + [target] = BaseContract._formatABIDataItemList( + inputAbi, + [target], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('removeAuthorizedAddress(address)') + .functions.removeAuthorizedAddress(target).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(target: string): string { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('removeAuthorizedAddress(address)').inputs; + [target] = BaseContract._formatABIDataItemList( + inputAbi, + [target], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('removeAuthorizedAddress(address)') + .functions.removeAuthorizedAddress(target).data; + return abiEncodedTransactionData; + }, + }; + public owner = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenTransferProxyContract; + const functionSignature = 'owner()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.owner() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'owner' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public authorized = { + async callAsync( + index_0: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + const self = (this as any) as TokenTransferProxyContract; + const functionSignature = 'authorized(address)'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [index_0] = BaseContract._formatABIDataItemList( + inputAbi, + [index_0], + BaseContract._bigNumberToString.bind(self), + ); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.authorized(index_0) as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'authorized' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public getAuthorizedAddresses = { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + const self = (this as any) as TokenTransferProxyContract; + const functionSignature = 'getAuthorizedAddresses()'; + const inputAbi = self._lookupAbi(functionSignature).inputs; + [] = BaseContract._formatABIDataItemList(inputAbi, [], BaseContract._bigNumberToString.bind(self)); + const ethersFunction = self + ._lookupEthersInterface(functionSignature) + .functions.getAuthorizedAddresses() as ethers.CallDescription; + const encodedData = ethersFunction.data; + const callDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: encodedData, + }); + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + let resultArray = ethersFunction.parse(rawCallResult); + const outputAbi = (_.find(self.abi, { name: 'getAuthorizedAddresses' }) as MethodAbi).outputs; + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._lowercaseAddress.bind(this), + ); + resultArray = BaseContract._formatABIDataItemList( + outputAbi, + resultArray, + BaseContract._bnToBigNumber.bind(this), + ); + return resultArray[0]; + }, + }; + public transferOwnership = { + async sendTransactionAsync(newOwner: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('transferOwnership(address)').inputs; + [newOwner] = BaseContract._formatABIDataItemList( + inputAbi, + [newOwner], + BaseContract._bigNumberToString.bind(self), + ); + const encodedData = self + ._lookupEthersInterface('transferOwnership(address)') + .functions.transferOwnership(newOwner).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { + ...txData, + data: encodedData, + }, + self.transferOwnership.estimateGasAsync.bind(self, newOwner), + ); + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + async estimateGasAsync(newOwner: string, txData: Partial = {}): Promise { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('transferOwnership(address)').inputs; + [newOwner] = BaseContract._formatABIDataItemList( + inputAbi, + [newOwner], + BaseContract._bigNumberToString.bind(this), + ); + const encodedData = self + ._lookupEthersInterface('transferOwnership(address)') + .functions.transferOwnership(newOwner).data; + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: encodedData, + }); + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + getABIEncodedTransactionData(newOwner: string): string { + const self = (this as any) as TokenTransferProxyContract; + const inputAbi = self._lookupAbi('transferOwnership(address)').inputs; + [newOwner] = BaseContract._formatABIDataItemList( + inputAbi, + [newOwner], + BaseContract._bigNumberToString.bind(self), + ); + const abiEncodedTransactionData = self + ._lookupEthersInterface('transferOwnership(address)') + .functions.transferOwnership(newOwner).data; + return abiEncodedTransactionData; + }, + }; + constructor(abi: ContractAbi, address: string, provider: Provider, defaults?: Partial) { + super(abi, address, provider, defaults); + classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']); + } +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/token_registry_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/token_registry_wrapper.ts new file mode 100644 index 000000000..5ae488172 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/token_registry_wrapper.ts @@ -0,0 +1,134 @@ +import { Token } from '@0xproject/types'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { artifacts } from '../artifacts'; +import { TokenMetadata } from '../types'; +import { assert } from '../utils/assert'; +import { constants } from '../utils/constants'; + +import { ContractWrapper } from './contract_wrapper'; +import { TokenRegistryContract } from './generated/token_registry'; + +/** + * This class includes all the functionality related to interacting with the 0x Token Registry smart contract. + */ +export class TokenRegistryWrapper extends ContractWrapper { + private _tokenRegistryContractIfExists?: TokenRegistryContract; + private _contractAddressIfExists?: string; + private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined { + if (metadata[0] === constants.NULL_ADDRESS) { + return undefined; + } + const token = { + address: metadata[0], + name: metadata[1], + symbol: metadata[2], + decimals: metadata[3], + }; + return token; + } + constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) { + super(web3Wrapper, networkId); + this._contractAddressIfExists = contractAddressIfExists; + } + /** + * Retrieves all the tokens currently listed in the Token Registry smart contract + * @return An array of objects that conform to the Token interface. + */ + public async getTokensAsync(): Promise { + const addresses = await this.getTokenAddressesAsync(); + const tokenPromises: Array> = _.map(addresses, async (address: string) => + this.getTokenIfExistsAsync(address), + ); + const tokens = await Promise.all(tokenPromises); + return tokens as Token[]; + } + /** + * Retrieves all the addresses of the tokens currently listed in the Token Registry smart contract + * @return An array of token addresses. + */ + public async getTokenAddressesAsync(): Promise { + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const addresses = await tokenRegistryContract.getTokenAddresses.callAsync(); + const lowerCaseAddresses = _.map(addresses, address => address.toLowerCase()); + return lowerCaseAddresses; + } + /** + * Retrieves a token by address currently listed in the Token Registry smart contract + * @return An object that conforms to the Token interface or undefined if token not found. + */ + public async getTokenIfExistsAsync(address: string): Promise { + assert.isETHAddressHex('address', address); + const normalizedAddress = address.toLowerCase(); + + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(normalizedAddress); + const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); + return token; + } + public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise { + assert.isString('symbol', symbol); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol); + if (addressIfExists === constants.NULL_ADDRESS) { + return undefined; + } + return addressIfExists; + } + public async getTokenAddressByNameIfExistsAsync(name: string): Promise { + assert.isString('name', name); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name); + if (addressIfExists === constants.NULL_ADDRESS) { + return undefined; + } + return addressIfExists; + } + public async getTokenBySymbolIfExistsAsync(symbol: string): Promise { + assert.isString('symbol', symbol); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol); + const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); + return token; + } + public async getTokenByNameIfExistsAsync(name: string): Promise { + assert.isString('name', name); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const metadata = await tokenRegistryContract.getTokenByName.callAsync(name); + const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); + return token; + } + /** + * Retrieves the Ethereum address of the TokenRegistry contract deployed on the network + * that the user-passed web3 provider is connected to. + * @returns The Ethereum address of the TokenRegistry contract being used. + */ + public getContractAddress(): string { + const contractAddress = this._getContractAddress( + artifacts.TokenRegistry, + this._contractAddressIfExists, + ); + return contractAddress; + } + private _invalidateContractInstance(): void { + delete this._tokenRegistryContractIfExists; + } + private async _getTokenRegistryContractAsync(): Promise { + if (!_.isUndefined(this._tokenRegistryContractIfExists)) { + return this._tokenRegistryContractIfExists; + } + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( + artifacts.TokenRegistry, + this._contractAddressIfExists, + ); + const contractInstance = new TokenRegistryContract( + abi, + address, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + this._tokenRegistryContractIfExists = contractInstance; + return this._tokenRegistryContractIfExists; + } +} diff --git a/packages/contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts new file mode 100644 index 000000000..ebd40e4d2 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts @@ -0,0 +1,75 @@ +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { artifacts } from '../artifacts'; +import { assert } from '../utils/assert'; + +import { ContractWrapper } from './contract_wrapper'; +import { TokenTransferProxyContract } from './generated/token_transfer_proxy'; + +/** + * This class includes the functionality related to interacting with the TokenTransferProxy contract. + */ +export class TokenTransferProxyWrapper extends ContractWrapper { + private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract; + private _contractAddressIfExists?: string; + constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) { + super(web3Wrapper, networkId); + this._contractAddressIfExists = contractAddressIfExists; + } + /** + * Check if the Exchange contract address is authorized by the TokenTransferProxy contract. + * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. + * @return Whether the exchangeContractAddress is authorized. + */ + public async isAuthorizedAsync(exchangeContractAddress: string): Promise { + assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress); + const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase(); + const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync(); + const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync( + normalizedExchangeContractAddress, + ); + return isAuthorized; + } + /** + * Get the list of all Exchange contract addresses authorized by the TokenTransferProxy contract. + * @return The list of authorized addresses. + */ + public async getAuthorizedAddressesAsync(): Promise { + const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync(); + const authorizedAddresses = await tokenTransferProxyContractInstance.getAuthorizedAddresses.callAsync(); + return authorizedAddresses; + } + /** + * Retrieves the Ethereum address of the TokenTransferProxy contract deployed on the network + * that the user-passed web3 provider is connected to. + * @returns The Ethereum address of the TokenTransferProxy contract being used. + */ + public getContractAddress(): string { + const contractAddress = this._getContractAddress( + artifacts.TokenTransferProxy, + this._contractAddressIfExists, + ); + return contractAddress; + } + private _invalidateContractInstance(): void { + delete this._tokenTransferProxyContractIfExists; + } + private async _getTokenTransferProxyContractAsync(): Promise { + if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) { + return this._tokenTransferProxyContractIfExists; + } + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( + artifacts.TokenTransferProxy, + this._contractAddressIfExists, + ); + const contractInstance = new TokenTransferProxyContract( + abi, + address, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + this._tokenTransferProxyContractIfExists = contractInstance; + return this._tokenTransferProxyContractIfExists; + } +} diff --git a/packages/contract-wrappers/src/contract_wrappers/token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/token_wrapper.ts new file mode 100644 index 000000000..844318c79 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/token_wrapper.ts @@ -0,0 +1,441 @@ +import { schemas } from '@0xproject/json-schemas'; +import { LogWithDecodedArgs } from '@0xproject/types'; +import { AbiDecoder, BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { artifacts } from '../artifacts'; +import { + BlockRange, + ContractWrappersError, + EventCallback, + IndexedFilterValues, + MethodOpts, + TransactionOpts, +} from '../types'; +import { assert } from '../utils/assert'; +import { constants } from '../utils/constants'; + +import { ContractWrapper } from './contract_wrapper'; +import { TokenContract, TokenContractEventArgs, TokenEvents } from './generated/token'; +import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper'; + +/** + * This class includes all the functionality related to interacting with ERC20 token contracts. + * All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances + * to the 0x Proxy smart contract. + */ +export class TokenWrapper extends ContractWrapper { + public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + private _tokenContractsByAddress: { [address: string]: TokenContract }; + private _tokenTransferProxyWrapper: TokenTransferProxyWrapper; + constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenTransferProxyWrapper: TokenTransferProxyWrapper) { + super(web3Wrapper, networkId); + this._tokenContractsByAddress = {}; + this._tokenTransferProxyWrapper = tokenTransferProxyWrapper; + } + /** + * Retrieves an owner's ERC20 token balance. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address whose balance you would like to check. + * @param methodOpts Optional arguments this method accepts. + * @return The owner's ERC20 token balance in base units. + */ + public async getBalanceAsync( + tokenAddress: string, + ownerAddress: string, + methodOpts?: MethodOpts, + ): Promise { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); + const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; + const txData = {}; + let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, defaultBlock); + // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber + balance = new BigNumber(balance); + return balance; + } + /** + * Sets the spender's allowance to a specified number of baseUnits on behalf of the owner address. + * Equivalent to the ERC20 spec method `approve`. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance + * for spenderAddress. + * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance. + * @param amountInBaseUnits The allowance amount you would like to set. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async setAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + spenderAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('spenderAddress', spenderAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedSpenderAddress = spenderAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); + + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); + const txHash = await tokenContract.approve.sendTransactionAsync(normalizedSpenderAddress, amountInBaseUnits, { + from: normalizedOwnerAddress, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, + }); + return txHash; + } + /** + * Sets the spender's allowance to an unlimited number of baseUnits on behalf of the owner address. + * Equivalent to the ERC20 spec method `approve`. + * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating + * allowances set to the max amount (e.g ZRX, WETH) + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance + * for spenderAddress. + * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async setUnlimitedAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + spenderAddress: string, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + assert.isETHAddressHex('spenderAddress', spenderAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + const normalizedSpenderAddress = spenderAddress.toLowerCase(); + const txHash = await this.setAllowanceAsync( + normalizedTokenAddress, + normalizedOwnerAddress, + normalizedSpenderAddress, + this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + txOpts, + ); + return txHash; + } + /** + * Retrieves the owners allowance in baseUnits set to the spender's address. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address whose allowance to spenderAddress + * you would like to retrieve. + * @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching. + * @param methodOpts Optional arguments this method accepts. + */ + public async getAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + spenderAddress: string, + methodOpts?: MethodOpts, + ): Promise { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + assert.isETHAddressHex('spenderAddress', spenderAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + const normalizedSpenderAddress = spenderAddress.toLowerCase(); + + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); + const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock; + const txData = {}; + let allowanceInBaseUnits = await tokenContract.allowance.callAsync( + normalizedOwnerAddress, + normalizedSpenderAddress, + txData, + defaultBlock, + ); + // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber + allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits); + return allowanceInBaseUnits; + } + /** + * Retrieves the owner's allowance in baseUnits set to the 0x proxy contract. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving. + * @param methodOpts Optional arguments this method accepts. + */ + public async getProxyAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + methodOpts?: MethodOpts, + ): Promise { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + + const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); + const allowanceInBaseUnits = await this.getAllowanceAsync( + normalizedTokenAddress, + normalizedOwnerAddress, + proxyAddress, + methodOpts, + ); + return allowanceInBaseUnits; + } + /** + * Sets the 0x proxy contract's allowance to a specified number of a tokens' baseUnits on behalf + * of an owner address. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance + * for the Proxy contract. + * @param amountInBaseUnits The allowance amount specified in baseUnits. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async setProxyAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); + + const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); + const txHash = await this.setAllowanceAsync( + normalizedTokenAddress, + normalizedOwnerAddress, + proxyAddress, + amountInBaseUnits, + txOpts, + ); + return txHash; + } + /** + * Sets the 0x proxy contract's allowance to a unlimited number of a tokens' baseUnits on behalf + * of an owner address. + * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating + * allowances set to the max amount (e.g ZRX, WETH) + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance + * for the Proxy contract. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async setUnlimitedProxyAllowanceAsync( + tokenAddress: string, + ownerAddress: string, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('ownerAddress', ownerAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedOwnerAddress = ownerAddress.toLowerCase(); + const txHash = await this.setProxyAllowanceAsync( + normalizedTokenAddress, + normalizedOwnerAddress, + this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + txOpts, + ); + return txHash; + } + /** + * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param fromAddress The hex encoded user Ethereum address that will send the funds. + * @param toAddress The hex encoded user Ethereum address that will receive the funds. + * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async transferAsync( + tokenAddress: string, + fromAddress: string, + toAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('tokenAddress', tokenAddress); + assert.isETHAddressHex('toAddress', toAddress); + await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedFromAddress = fromAddress.toLowerCase(); + const normalizedToAddress = toAddress.toLowerCase(); + assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); + + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); + + const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress); + if (fromAddressBalance.lessThan(amountInBaseUnits)) { + throw new Error(ContractWrappersError.InsufficientBalanceForTransfer); + } + + const txHash = await tokenContract.transfer.sendTransactionAsync(normalizedToAddress, amountInBaseUnits, { + from: normalizedFromAddress, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, + }); + return txHash; + } + /** + * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`. + * Requires the fromAddress to have sufficient funds and to have approved an allowance of + * `amountInBaseUnits` to `senderAddress`. + * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. + * @param fromAddress The hex encoded user Ethereum address whose funds are being sent. + * @param toAddress The hex encoded user Ethereum address that will receive the funds. + * @param senderAddress The hex encoded user Ethereum address whose initiates the fund transfer. The + * `fromAddress` must have set an allowance to the `senderAddress` + * before this call. + * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer. + * @param txOpts Transaction parameters. + * @return Transaction hash. + */ + public async transferFromAsync( + tokenAddress: string, + fromAddress: string, + toAddress: string, + senderAddress: string, + amountInBaseUnits: BigNumber, + txOpts: TransactionOpts = {}, + ): Promise { + assert.isETHAddressHex('toAddress', toAddress); + assert.isETHAddressHex('fromAddress', fromAddress); + assert.isETHAddressHex('tokenAddress', tokenAddress); + await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); + const normalizedToAddress = toAddress.toLowerCase(); + const normalizedFromAddress = fromAddress.toLowerCase(); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const normalizedSenderAddress = senderAddress.toLowerCase(); + assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); + + const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); + + const fromAddressAllowance = await this.getAllowanceAsync( + normalizedTokenAddress, + normalizedFromAddress, + normalizedSenderAddress, + ); + if (fromAddressAllowance.lessThan(amountInBaseUnits)) { + throw new Error(ContractWrappersError.InsufficientAllowanceForTransfer); + } + + const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress); + if (fromAddressBalance.lessThan(amountInBaseUnits)) { + throw new Error(ContractWrappersError.InsufficientBalanceForTransfer); + } + + const txHash = await tokenContract.transferFrom.sendTransactionAsync( + normalizedFromAddress, + normalizedToAddress, + amountInBaseUnits, + { + from: normalizedSenderAddress, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, + }, + ); + return txHash; + } + /** + * Subscribe to an event type emitted by the Token contract. + * @param tokenAddress The hex encoded address where the ERC20 token is deployed. + * @param eventName The token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @return Subscription token used later to unsubscribe + */ + public subscribe( + tokenAddress: string, + eventName: TokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + ): string { + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscribe( + normalizedTokenAddress, + eventName, + indexFilterValues, + artifacts.Token.abi, + callback, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super._unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param tokenAddress An address of the token that emitted the logs. + * @param eventName The token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + tokenAddress: string, + eventName: TokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.isETHAddressHex('tokenAddress', tokenAddress); + const normalizedTokenAddress = tokenAddress.toLowerCase(); + assert.doesBelongToStringEnum('eventName', eventName, TokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._getLogsAsync( + normalizedTokenAddress, + eventName, + blockRange, + indexFilterValues, + artifacts.Token.abi, + ); + return logs; + } + private _invalidateContractInstances(): void { + this.unsubscribeAll(); + this._tokenContractsByAddress = {}; + } + private async _getTokenContractAsync(tokenAddress: string): Promise { + const normalizedTokenAddress = tokenAddress.toLowerCase(); + let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress]; + if (!_.isUndefined(tokenContract)) { + return tokenContract; + } + const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync( + artifacts.Token, + normalizedTokenAddress, + ); + const contractInstance = new TokenContract( + abi, + address, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + tokenContract = contractInstance; + this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract; + return tokenContract; + } +} diff --git a/packages/contract-wrappers/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts b/packages/contract-wrappers/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts new file mode 100644 index 000000000..5017d879a --- /dev/null +++ b/packages/contract-wrappers/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts @@ -0,0 +1,28 @@ +import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils'; +import { BlockParamLiteral } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +import { TokenWrapper } from '../contract_wrappers/token_wrapper'; + +export class SimpleBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { + private _tokenWrapper: TokenWrapper; + private _defaultBlock: BlockParamLiteral; + constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { + this._tokenWrapper = token; + this._defaultBlock = defaultBlock; + } + public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const balance = this._tokenWrapper.getBalanceAsync(tokenAddress, userAddress, methodOpts); + return balance; + } + public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const proxyAllowance = this._tokenWrapper.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts); + return proxyAllowance; + } +} diff --git a/packages/contract-wrappers/src/fetchers/simple_order_filled_cancelled_fetcher.ts b/packages/contract-wrappers/src/fetchers/simple_order_filled_cancelled_fetcher.ts new file mode 100644 index 000000000..b6f31b205 --- /dev/null +++ b/packages/contract-wrappers/src/fetchers/simple_order_filled_cancelled_fetcher.ts @@ -0,0 +1,34 @@ +import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils'; +import { BlockParamLiteral } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; + +export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher { + private _exchangeWrapper: ExchangeWrapper; + private _defaultBlock: BlockParamLiteral; + constructor(exchange: ExchangeWrapper, defaultBlock: BlockParamLiteral) { + this._exchangeWrapper = exchange; + this._defaultBlock = defaultBlock; + } + public async getFilledTakerAmountAsync(orderHash: string): Promise { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const filledTakerAmount = this._exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); + return filledTakerAmount; + } + public async getCancelledTakerAmountAsync(orderHash: string): Promise { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const cancelledTakerAmount = this._exchangeWrapper.getCancelledTakerAmountAsync(orderHash, methodOpts); + return cancelledTakerAmount; + } + public async getUnavailableTakerAmountAsync(orderHash: string) { + return this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + } + public getZRXTokenAddress(): string { + return this._exchangeWrapper.getZRXTokenAddress(); + } +} diff --git a/packages/contract-wrappers/src/globals.d.ts b/packages/contract-wrappers/src/globals.d.ts new file mode 100644 index 000000000..94e63a32d --- /dev/null +++ b/packages/contract-wrappers/src/globals.d.ts @@ -0,0 +1,6 @@ +declare module '*.json' { + const json: any; + /* tslint:disable */ + export default json; + /* tslint:enable */ +} diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts new file mode 100644 index 000000000..f88313eb1 --- /dev/null +++ b/packages/contract-wrappers/src/index.ts @@ -0,0 +1,68 @@ +export { ContractWrappers } from './contract_wrappers'; +export { ExchangeWrapper } from './contract_wrappers/exchange_wrapper'; +export { TokenWrapper } from './contract_wrappers/token_wrapper'; +export { TokenRegistryWrapper } from './contract_wrappers/token_registry_wrapper'; +export { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper'; +export { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_proxy_wrapper'; + +export { + ContractWrappersError, + EventCallback, + ContractEvent, + Token, + IndexedFilterValues, + BlockRange, + OrderCancellationRequest, + OrderFillRequest, + ContractEventArgs, + ZeroExContractConfig, + MethodOpts, + OrderTransactionOpts, + TransactionOpts, + LogEvent, + DecodedLogEvent, + OnOrderStateChangeCallback, +} from './types'; + +export { + BlockParamLiteral, + FilterObject, + BlockParam, + ContractEventArg, + ExchangeContractErrs, + LogWithDecodedArgs, + Order, + Provider, + SignedOrder, + ECSignature, + OrderStateValid, + OrderStateInvalid, + OrderState, + TransactionReceipt, + TransactionReceiptWithDecodedLogs, +} from '@0xproject/types'; + +export { + EtherTokenContractEventArgs, + WithdrawalContractEventArgs, + DepositContractEventArgs, + EtherTokenEvents, +} from './contract_wrappers/generated/ether_token'; + +export { + TransferContractEventArgs, + ApprovalContractEventArgs, + TokenContractEventArgs, + TokenEvents, +} from './contract_wrappers/generated/token'; + +export { + LogErrorContractEventArgs, + LogCancelContractEventArgs, + LogFillContractEventArgs, + ExchangeContractEventArgs, + ExchangeEvents, +} from './contract_wrappers/generated/exchange'; + +export { BalanceAndProxyAllowanceLazyStore } from './stores/balance_proxy_allowance_lazy_store'; +export { OrderFilledCancelledLazyStore } from './stores/order_filled_cancelled_lazy_store'; diff --git a/packages/contract-wrappers/src/monorepo_scripts/postpublish.ts b/packages/contract-wrappers/src/monorepo_scripts/postpublish.ts new file mode 100644 index 000000000..dcb99d0f7 --- /dev/null +++ b/packages/contract-wrappers/src/monorepo_scripts/postpublish.ts @@ -0,0 +1,8 @@ +import { postpublishUtils } from '@0xproject/monorepo-scripts'; + +import * as packageJSON from '../package.json'; +import * as tsConfigJSON from '../tsconfig.json'; + +const cwd = `${__dirname}/..`; +// tslint:disable-next-line:no-floating-promises +postpublishUtils.runAsync(packageJSON, tsConfigJSON, cwd); diff --git a/packages/contract-wrappers/src/schemas/zero_ex_contract_config_schema.ts b/packages/contract-wrappers/src/schemas/zero_ex_contract_config_schema.ts new file mode 100644 index 000000000..eec386643 --- /dev/null +++ b/packages/contract-wrappers/src/schemas/zero_ex_contract_config_schema.ts @@ -0,0 +1,5 @@ +export const zeroExContractConfigSchema = { + id: '/ZeroExContractConfig', + oneOf: [{ $ref: '/ZeroExContractPrivateNetworkConfig' }, { $ref: '/ZeroExContractPublicNetworkConfig' }], + type: 'object', +}; diff --git a/packages/contract-wrappers/src/schemas/zero_ex_contract_private_network_config_schema.ts b/packages/contract-wrappers/src/schemas/zero_ex_contract_private_network_config_schema.ts new file mode 100644 index 000000000..6d93d4e60 --- /dev/null +++ b/packages/contract-wrappers/src/schemas/zero_ex_contract_private_network_config_schema.ts @@ -0,0 +1,35 @@ +export const zeroExContractPrivateNetworkConfigSchema = { + id: '/ZeroExContractPrivateNetworkConfig', + properties: { + networkId: { + type: 'number', + minimum: 1, + }, + gasPrice: { $ref: '/Number' }, + zrxContractAddress: { $ref: '/Address' }, + exchangeContractAddress: { $ref: '/Address' }, + tokenRegistryContractAddress: { $ref: '/Address' }, + tokenTransferProxyContractAddress: { $ref: '/Address' }, + orderWatcherConfig: { + type: 'object', + properties: { + pollingIntervalMs: { + type: 'number', + minimum: 0, + }, + numConfirmations: { + type: 'number', + minimum: 0, + }, + }, + }, + }, + type: 'object', + required: [ + 'networkId', + 'zrxContractAddress', + 'exchangeContractAddress', + 'tokenRegistryContractAddress', + 'tokenTransferProxyContractAddress', + ], +}; diff --git a/packages/contract-wrappers/src/schemas/zero_ex_contract_public_network_config_schema.ts b/packages/contract-wrappers/src/schemas/zero_ex_contract_public_network_config_schema.ts new file mode 100644 index 000000000..79a241cd2 --- /dev/null +++ b/packages/contract-wrappers/src/schemas/zero_ex_contract_public_network_config_schema.ts @@ -0,0 +1,29 @@ +export const zeroExContractPublicNetworkConfigSchema = { + id: '/ZeroExContractPublicNetworkConfig', + properties: { + networkId: { + type: 'number', + enum: [1, 3, 4, 42, 50], + }, + gasPrice: { $ref: '/Number' }, + zrxContractAddress: { $ref: '/Address' }, + exchangeContractAddress: { $ref: '/Address' }, + tokenRegistryContractAddress: { $ref: '/Address' }, + tokenTransferProxyContractAddress: { $ref: '/Address' }, + orderWatcherConfig: { + type: 'object', + properties: { + pollingIntervalMs: { + type: 'number', + minimum: 0, + }, + numConfirmations: { + type: 'number', + minimum: 0, + }, + }, + }, + }, + type: 'object', + required: ['networkId'], +}; diff --git a/packages/contract-wrappers/src/stores/balance_proxy_allowance_lazy_store.ts b/packages/contract-wrappers/src/stores/balance_proxy_allowance_lazy_store.ts new file mode 100644 index 000000000..614195157 --- /dev/null +++ b/packages/contract-wrappers/src/stores/balance_proxy_allowance_lazy_store.ts @@ -0,0 +1,91 @@ +import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils'; +import { BlockParamLiteral } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { TokenWrapper } from '../contract_wrappers/token_wrapper'; + +/** + * Copy on read store for balances/proxyAllowances of tokens/accounts + */ +export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceFetcher { + private _tokenWrapper: TokenWrapper; + private _defaultBlock: BlockParamLiteral; + private _balance: { + [tokenAddress: string]: { + [userAddress: string]: BigNumber; + }; + }; + private _proxyAllowance: { + [tokenAddress: string]: { + [userAddress: string]: BigNumber; + }; + }; + constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { + this._tokenWrapper = token; + this._defaultBlock = defaultBlock; + this._balance = {}; + this._proxyAllowance = {}; + } + public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise { + if (_.isUndefined(this._balance[tokenAddress]) || _.isUndefined(this._balance[tokenAddress][userAddress])) { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const balance = await this._tokenWrapper.getBalanceAsync(tokenAddress, userAddress, methodOpts); + this.setBalance(tokenAddress, userAddress, balance); + } + const cachedBalance = this._balance[tokenAddress][userAddress]; + return cachedBalance; + } + public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void { + if (_.isUndefined(this._balance[tokenAddress])) { + this._balance[tokenAddress] = {}; + } + this._balance[tokenAddress][userAddress] = balance; + } + public deleteBalance(tokenAddress: string, userAddress: string): void { + if (!_.isUndefined(this._balance[tokenAddress])) { + delete this._balance[tokenAddress][userAddress]; + if (_.isEmpty(this._balance[tokenAddress])) { + delete this._balance[tokenAddress]; + } + } + } + public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise { + if ( + _.isUndefined(this._proxyAllowance[tokenAddress]) || + _.isUndefined(this._proxyAllowance[tokenAddress][userAddress]) + ) { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const proxyAllowance = await this._tokenWrapper.getProxyAllowanceAsync( + tokenAddress, + userAddress, + methodOpts, + ); + this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance); + } + const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress]; + return cachedProxyAllowance; + } + public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void { + if (_.isUndefined(this._proxyAllowance[tokenAddress])) { + this._proxyAllowance[tokenAddress] = {}; + } + this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance; + } + public deleteProxyAllowance(tokenAddress: string, userAddress: string): void { + if (!_.isUndefined(this._proxyAllowance[tokenAddress])) { + delete this._proxyAllowance[tokenAddress][userAddress]; + if (_.isEmpty(this._proxyAllowance[tokenAddress])) { + delete this._proxyAllowance[tokenAddress]; + } + } + } + public deleteAll(): void { + this._balance = {}; + this._proxyAllowance = {}; + } +} diff --git a/packages/contract-wrappers/src/stores/order_filled_cancelled_lazy_store.ts b/packages/contract-wrappers/src/stores/order_filled_cancelled_lazy_store.ts new file mode 100644 index 000000000..b554191a2 --- /dev/null +++ b/packages/contract-wrappers/src/stores/order_filled_cancelled_lazy_store.ts @@ -0,0 +1,73 @@ +import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils'; +import { BlockParamLiteral } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; + +/** + * Copy on read store for filled/cancelled taker amounts + */ +export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancelledFetcher { + private _exchangeWrapper: ExchangeWrapper; + private _defaultBlock: BlockParamLiteral; + private _filledTakerAmount: { + [orderHash: string]: BigNumber; + }; + private _cancelledTakerAmount: { + [orderHash: string]: BigNumber; + }; + constructor(exchange: ExchangeWrapper, defaultBlock: BlockParamLiteral) { + this._exchangeWrapper = exchange; + this._defaultBlock = defaultBlock; + this._filledTakerAmount = {}; + this._cancelledTakerAmount = {}; + } + public async getFilledTakerAmountAsync(orderHash: string): Promise { + if (_.isUndefined(this._filledTakerAmount[orderHash])) { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const filledTakerAmount = await this._exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); + this.setFilledTakerAmount(orderHash, filledTakerAmount); + } + const cachedFilled = this._filledTakerAmount[orderHash]; + return cachedFilled; + } + public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void { + this._filledTakerAmount[orderHash] = filledTakerAmount; + } + public deleteFilledTakerAmount(orderHash: string): void { + delete this._filledTakerAmount[orderHash]; + } + public async getCancelledTakerAmountAsync(orderHash: string): Promise { + if (_.isUndefined(this._cancelledTakerAmount[orderHash])) { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const cancelledTakerAmount = await this._exchangeWrapper.getCancelledTakerAmountAsync( + orderHash, + methodOpts, + ); + this.setCancelledTakerAmount(orderHash, cancelledTakerAmount); + } + const cachedCancelled = this._cancelledTakerAmount[orderHash]; + return cachedCancelled; + } + public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void { + this._cancelledTakerAmount[orderHash] = cancelledTakerAmount; + } + public deleteCancelledTakerAmount(orderHash: string): void { + delete this._cancelledTakerAmount[orderHash]; + } + public deleteAll(): void { + this._filledTakerAmount = {}; + this._cancelledTakerAmount = {}; + } + public async getUnavailableTakerAmountAsync(orderHash: string) { + return this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + } + public getZRXTokenAddress(): string { + return this._exchangeWrapper.getZRXTokenAddress(); + } +} diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts new file mode 100644 index 000000000..e69701820 --- /dev/null +++ b/packages/contract-wrappers/src/types.ts @@ -0,0 +1,187 @@ +import { BigNumber } from '@0xproject/utils'; + +import { + BlockParam, + BlockParamLiteral, + ContractAbi, + ContractEventArg, + ExchangeContractErrs, + FilterObject, + LogEntryEvent, + LogWithDecodedArgs, + Order, + OrderState, + SignedOrder, +} from '@0xproject/types'; + +import { EtherTokenContractEventArgs, EtherTokenEvents } from './contract_wrappers/generated/ether_token'; +import { ExchangeContractEventArgs, ExchangeEvents } from './contract_wrappers/generated/exchange'; +import { TokenContractEventArgs, TokenEvents } from './contract_wrappers/generated/token'; + +export enum ContractWrappersError { + ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST', + ZRXContractDoesNotExist = 'ZRX_CONTRACT_DOES_NOT_EXIST', + EtherTokenContractDoesNotExist = 'ETHER_TOKEN_CONTRACT_DOES_NOT_EXIST', + TokenTransferProxyContractDoesNotExist = 'TOKEN_TRANSFER_PROXY_CONTRACT_DOES_NOT_EXIST', + TokenRegistryContractDoesNotExist = 'TOKEN_REGISTRY_CONTRACT_DOES_NOT_EXIST', + TokenContractDoesNotExist = 'TOKEN_CONTRACT_DOES_NOT_EXIST', + ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK', + InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', + InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER', + InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT', + InsufficientWEthBalanceForWithdrawal = 'INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL', + InvalidJump = 'INVALID_JUMP', + OutOfGas = 'OUT_OF_GAS', + SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND', + SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT', +} + +export enum InternalContractWrappersError { + NoAbiDecoder = 'NO_ABI_DECODER', + ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', + WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY', +} + +export type LogEvent = LogEntryEvent; +export interface DecodedLogEvent { + isRemoved: boolean; + log: LogWithDecodedArgs; +} + +export type EventCallback = (err: null | Error, log?: DecodedLogEvent) => void; + +export enum ExchangeContractErrCodes { + ERROR_FILL_EXPIRED, // Order has already expired + ERROR_FILL_NO_VALUE, // Order has already been fully filled or cancelled + ERROR_FILL_TRUNCATION, // Rounding error too large + ERROR_FILL_BALANCE_ALLOWANCE, // Insufficient balance or allowance for token transfer + ERROR_CANCEL_EXPIRED, // Order has already expired + ERROR_CANCEL_NO_VALUE, // Order has already been fully filled or cancelled +} + +export interface ContractEvent { + logIndex: number; + transactionIndex: number; + transactionHash: string; + blockHash: string; + blockNumber: number; + address: string; + type: string; + event: string; + args: ContractEventArgs; +} + +export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs; + +// [address, name, symbol, decimals, ipfsHash, swarmHash] +export type TokenMetadata = [string, string, string, number, string, string]; + +export interface Token { + name: string; + address: string; + symbol: string; + decimals: number; +} + +export interface TxOpts { + from: string; + gas?: number; + value?: BigNumber; + gasPrice?: BigNumber; +} + +export interface TokenAddressBySymbol { + [symbol: string]: string; +} + +export type ContractEvents = TokenEvents | ExchangeEvents | EtherTokenEvents; + +export interface IndexedFilterValues { + [index: string]: ContractEventArg; +} + +export interface BlockRange { + fromBlock: BlockParam; + toBlock: BlockParam; +} + +export interface OrderCancellationRequest { + order: Order | SignedOrder; + takerTokenCancelAmount: BigNumber; +} + +export interface OrderFillRequest { + signedOrder: SignedOrder; + takerTokenFillAmount: BigNumber; +} + +export type AsyncMethod = (...args: any[]) => Promise; +export type SyncMethod = (...args: any[]) => any; + +/** + * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc) + * gasPrice: Gas price to use with every transaction + * exchangeContractAddress: The address of an exchange contract to use + * zrxContractAddress: The address of the ZRX contract to use + * tokenRegistryContractAddress: The address of a token registry contract to use + * tokenTransferProxyContractAddress: The address of the token transfer proxy contract to use + * orderWatcherConfig: All the configs related to the orderWatcher + */ +export interface ZeroExContractConfig { + networkId: number; + gasPrice?: BigNumber; + exchangeContractAddress?: string; + zrxContractAddress?: string; + tokenRegistryContractAddress?: string; + tokenTransferProxyContractAddress?: string; +} + +/** + * expectedFillTakerTokenAmount: If specified, the validation method will ensure that the + * supplied order maker has a sufficient allowance/balance to fill this amount of the order's + * takerTokenAmount. If not specified, the validation method ensures that the maker has a sufficient + * allowance/balance to fill the entire remaining order amount. + */ +export interface ValidateOrderFillableOpts { + expectedFillTakerTokenAmount?: BigNumber; +} + +/** + * defaultBlock: The block up to which to query the blockchain state. Setting this to a historical block number + * let's the user query the blockchain's state at an arbitrary point in time. In order for this to work, the + * backing Ethereum node must keep the entire historical state of the chain (e.g setting `--pruning=archive` + * flag when running Parity). + */ +export interface MethodOpts { + defaultBlock?: BlockParam; +} + +/** + * gasPrice: Gas price in Wei to use for a transaction + * gasLimit: The amount of gas to send with a transaction + */ +export interface TransactionOpts { + gasPrice?: BigNumber; + gasLimit?: number; +} + +/** + * shouldValidate: Flag indicating whether the library should make attempts to validate a transaction before + * broadcasting it. For example, order has a valid signature, maker has sufficient funds, etc. Default=true. + */ +export interface OrderTransactionOpts extends TransactionOpts { + shouldValidate?: boolean; +} + +export enum TradeSide { + Maker = 'maker', + Taker = 'taker', +} + +export enum TransferType { + Trade = 'trade', + Fee = 'fee', +} + +export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void; +// tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/utils/assert.ts b/packages/contract-wrappers/src/utils/assert.ts new file mode 100644 index 000000000..2588a4d09 --- /dev/null +++ b/packages/contract-wrappers/src/utils/assert.ts @@ -0,0 +1,31 @@ +import { assert as sharedAssert } from '@0xproject/assert'; +// We need those two unused imports because they're actually used by sharedAssert which gets injected here +// tslint:disable-next-line:no-unused-variable +import { Schema } from '@0xproject/json-schemas'; +// tslint:disable-next-line:no-unused-variable +import { ECSignature } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { isValidSignature } from '@0xproject/order-utils'; + +export const assert = { + ...sharedAssert, + isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) { + const isValid = isValidSignature(orderHash, ecSignature, signerAddress); + this.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`); + }, + async isSenderAddressAsync( + variableName: string, + senderAddressHex: string, + web3Wrapper: Web3Wrapper, + ): Promise { + sharedAssert.isETHAddressHex(variableName, senderAddressHex); + const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex); + sharedAssert.assert( + isSenderAddressAvailable, + `Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`, + ); + }, +}; diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts new file mode 100644 index 000000000..07da6745d --- /dev/null +++ b/packages/contract-wrappers/src/utils/constants.ts @@ -0,0 +1,11 @@ +import { BigNumber } from '@0xproject/utils'; + +export const constants = { + NULL_ADDRESS: '0x0000000000000000000000000000000000000000', + TESTRPC_NETWORK_ID: 50, + INVALID_JUMP_PATTERN: 'invalid JUMP at', + OUT_OF_GAS_PATTERN: 'out of gas', + INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string', + UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), + DEFAULT_BLOCK_POLLING_INTERVAL: 1000, +}; diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts new file mode 100644 index 000000000..64123143c --- /dev/null +++ b/packages/contract-wrappers/src/utils/decorators.ts @@ -0,0 +1,91 @@ +import * as _ from 'lodash'; + +import { AsyncMethod, ContractWrappersError, SyncMethod } from '../types'; + +import { constants } from './constants'; + +type ErrorTransformer = (err: Error) => Error; + +const contractCallErrorTransformer = (error: Error) => { + if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) { + return new Error(ContractWrappersError.InvalidJump); + } + if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) { + return new Error(ContractWrappersError.OutOfGas); + } + return error; +}; + +const schemaErrorTransformer = (error: Error) => { + if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) { + const errMsg = + 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS'; + return new Error(errMsg); + } + return error; +}; + +/** + * Source: https://stackoverflow.com/a/29837695/3546986 + */ +const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { + const asyncErrorHandlingDecorator = ( + target: object, + key: string | symbol, + descriptor: TypedPropertyDescriptor, + ) => { + const originalMethod = descriptor.value as AsyncMethod; + + // Do not use arrow syntax here. Use a function expression in + // order to use the correct value of `this` in this method + // tslint:disable-next-line:only-arrow-functions + descriptor.value = async function(...args: any[]) { + try { + const result = await originalMethod.apply(this, args); + return result; + } catch (error) { + const transformedError = errorTransformer(error); + throw transformedError; + } + }; + + return descriptor; + }; + + return asyncErrorHandlingDecorator; +}; + +const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { + const syncErrorHandlingDecorator = ( + target: object, + key: string | symbol, + descriptor: TypedPropertyDescriptor, + ) => { + const originalMethod = descriptor.value as SyncMethod; + + // Do not use arrow syntax here. Use a function expression in + // order to use the correct value of `this` in this method + // tslint:disable-next-line:only-arrow-functions + descriptor.value = function(...args: any[]) { + try { + const result = originalMethod.apply(this, args); + return result; + } catch (error) { + const transformedError = errorTransformer(error); + throw transformedError; + } + }; + + return descriptor; + }; + + return syncErrorHandlingDecorator; +}; + +// _.flow(f, g) = f ∘ g +const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer); + +export const decorators = { + asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer), + syncZeroExErrorHandler: syncErrorHandlerFactory(zeroExErrorTransformer), +}; diff --git a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts new file mode 100644 index 000000000..b575285a1 --- /dev/null +++ b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts @@ -0,0 +1,115 @@ +import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { TokenWrapper } from '../contract_wrappers/token_wrapper'; +import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; +import { TradeSide, TransferType } from '../types'; +import { constants } from '../utils/constants'; + +enum FailureReason { + Balance = 'balance', + ProxyAllowance = 'proxyAllowance', +} + +const ERR_MSG_MAPPING = { + [FailureReason.Balance]: { + [TradeSide.Maker]: { + [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerBalance, + [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeBalance, + }, + [TradeSide.Taker]: { + [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerBalance, + [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeBalance, + }, + }, + [FailureReason.ProxyAllowance]: { + [TradeSide.Maker]: { + [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerAllowance, + [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeAllowance, + }, + [TradeSide.Taker]: { + [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerAllowance, + [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeAllowance, + }, + }, +}; + +export class ExchangeTransferSimulator { + private _store: BalanceAndProxyAllowanceLazyStore; + private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; + private static _throwValidationError( + failureReason: FailureReason, + tradeSide: TradeSide, + transferType: TransferType, + ): never { + const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; + throw new Error(errMsg); + } + constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { + this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock); + this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + } + /** + * Simulates transferFrom call performed by a proxy + * @param tokenAddress Address of the token to be transferred + * @param from Owner of the transferred tokens + * @param to Recipient of the transferred tokens + * @param amountInBaseUnits The amount of tokens being transferred + * @param tradeSide Is Maker/Taker transferring + * @param transferType Is it a fee payment or a value transfer + */ + public async transferFromAsync( + tokenAddress: string, + from: string, + to: string, + amountInBaseUnits: BigNumber, + tradeSide: TradeSide, + transferType: TransferType, + ): Promise { + // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/ + // allowances for the taker. We do however, want to increase the balance of the maker since the maker + // might be relying on those funds to fill subsequent orders or pay the order's fees. + if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) { + await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); + return; + } + const balance = await this._store.getBalanceAsync(tokenAddress, from); + const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from); + if (proxyAllowance.lessThan(amountInBaseUnits)) { + ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType); + } + if (balance.lessThan(amountInBaseUnits)) { + ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType); + } + await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits); + await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits); + await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); + } + private async _decreaseProxyAllowanceAsync( + tokenAddress: string, + userAddress: string, + amountInBaseUnits: BigNumber, + ): Promise { + const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress); + if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { + this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); + } + } + private async _increaseBalanceAsync( + tokenAddress: string, + userAddress: string, + amountInBaseUnits: BigNumber, + ): Promise { + const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); + this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits)); + } + private async _decreaseBalanceAsync( + tokenAddress: string, + userAddress: string, + amountInBaseUnits: BigNumber, + ): Promise { + const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); + this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); + } +} diff --git a/packages/contract-wrappers/src/utils/filter_utils.ts b/packages/contract-wrappers/src/utils/filter_utils.ts new file mode 100644 index 000000000..c5df7321e --- /dev/null +++ b/packages/contract-wrappers/src/utils/filter_utils.ts @@ -0,0 +1,95 @@ +import { + ConstructorAbi, + ContractAbi, + EventAbi, + FallbackAbi, + FilterObject, + LogEntry, + MethodAbi, +} from '@0xproject/types'; +import * as ethUtil from 'ethereumjs-util'; +import * as jsSHA3 from 'js-sha3'; +import * as _ from 'lodash'; +import * as uuid from 'uuid/v4'; + +import { BlockRange, ContractEvents, IndexedFilterValues } from '../types'; + +const TOPIC_LENGTH = 32; + +export const filterUtils = { + generateUUID(): string { + return uuid(); + }, + getFilter( + address: string, + eventName: ContractEvents, + indexFilterValues: IndexedFilterValues, + abi: ContractAbi, + blockRange?: BlockRange, + ): FilterObject { + const eventAbi = _.find(abi, { name: eventName }) as EventAbi; + const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName); + const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature)); + const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues); + const topics = [topicForEventSignature, ...topicsForIndexedArgs]; + let filter: FilterObject = { + address, + topics, + }; + if (!_.isUndefined(blockRange)) { + filter = { + ...blockRange, + ...filter, + }; + } + return filter; + }, + getEventSignatureFromAbiByName(eventAbi: EventAbi, eventName: ContractEvents): string { + const types = _.map(eventAbi.inputs, 'type'); + const signature = `${eventAbi.name}(${types.join(',')})`; + return signature; + }, + getTopicsForIndexedArgs(abi: EventAbi, indexFilterValues: IndexedFilterValues): Array { + const topics: Array = []; + for (const eventInput of abi.inputs) { + if (!eventInput.indexed) { + continue; + } + if (_.isUndefined(indexFilterValues[eventInput.name])) { + // Null is a wildcard topic in a JSON-RPC call + topics.push(null); + } else { + const value = indexFilterValues[eventInput.name] as string; + const buffer = ethUtil.toBuffer(value); + const paddedBuffer = ethUtil.setLengthLeft(buffer, TOPIC_LENGTH); + const topic = ethUtil.bufferToHex(paddedBuffer); + topics.push(topic); + } + } + return topics; + }, + matchesFilter(log: LogEntry, filter: FilterObject): boolean { + if (!_.isUndefined(filter.address) && log.address !== filter.address) { + return false; + } + if (!_.isUndefined(filter.topics)) { + return filterUtils.matchesTopics(log.topics, filter.topics); + } + return true; + }, + matchesTopics(logTopics: string[], filterTopics: Array): boolean { + const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils)); + const matchesTopics = _.every(matchesTopic); + return matchesTopics; + }, + matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean { + if (_.isArray(filterTopic)) { + return _.includes(filterTopic, logTopic); + } + if (_.isString(filterTopic)) { + return filterTopic === logTopic; + } + // null topic is a wildcard + return true; + }, +}; diff --git a/packages/contract-wrappers/src/utils/order_validation_utils.ts b/packages/contract-wrappers/src/utils/order_validation_utils.ts new file mode 100644 index 000000000..36dfbd800 --- /dev/null +++ b/packages/contract-wrappers/src/utils/order_validation_utils.ts @@ -0,0 +1,198 @@ +import { getOrderHashHex, isValidSignature, OrderError } from '@0xproject/order-utils'; +import { ExchangeContractErrs, Order, SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { ContractWrappersError, TradeSide, TransferType } from '../types'; +import { constants } from '../utils/constants'; +import { utils } from '../utils/utils'; + +import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; + +export class OrderValidationUtils { + private _exchangeWrapper: ExchangeWrapper; + public static validateCancelOrderThrowIfInvalid( + order: Order, + cancelTakerTokenAmount: BigNumber, + unavailableTakerTokenAmount: BigNumber, + ): void { + if (cancelTakerTokenAmount.eq(0)) { + throw new Error(ExchangeContractErrs.OrderCancelAmountZero); + } + if (order.takerTokenAmount.eq(unavailableTakerTokenAmount)) { + throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); + } + const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); + if (order.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { + throw new Error(ExchangeContractErrs.OrderCancelExpired); + } + } + public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + senderAddress: string, + zrxTokenAddress: string, + ): Promise { + const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount( + fillTakerTokenAmount, + signedOrder.takerTokenAmount, + signedOrder.makerTokenAmount, + ); + await exchangeTradeEmulator.transferFromAsync( + signedOrder.makerTokenAddress, + signedOrder.maker, + senderAddress, + fillMakerTokenAmount, + TradeSide.Maker, + TransferType.Trade, + ); + await exchangeTradeEmulator.transferFromAsync( + signedOrder.takerTokenAddress, + senderAddress, + signedOrder.maker, + fillTakerTokenAmount, + TradeSide.Taker, + TransferType.Trade, + ); + const makerFeeAmount = OrderValidationUtils._getPartialAmount( + fillTakerTokenAmount, + signedOrder.takerTokenAmount, + signedOrder.makerFee, + ); + await exchangeTradeEmulator.transferFromAsync( + zrxTokenAddress, + signedOrder.maker, + signedOrder.feeRecipient, + makerFeeAmount, + TradeSide.Maker, + TransferType.Fee, + ); + const takerFeeAmount = OrderValidationUtils._getPartialAmount( + fillTakerTokenAmount, + signedOrder.takerTokenAmount, + signedOrder.takerFee, + ); + await exchangeTradeEmulator.transferFromAsync( + zrxTokenAddress, + senderAddress, + signedOrder.feeRecipient, + takerFeeAmount, + TradeSide.Taker, + TransferType.Fee, + ); + } + private static _validateRemainingFillAmountNotZeroOrThrow( + takerTokenAmount: BigNumber, + unavailableTakerTokenAmount: BigNumber, + ) { + if (takerTokenAmount.eq(unavailableTakerTokenAmount)) { + throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); + } + } + private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) { + const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); + if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { + throw new Error(ExchangeContractErrs.OrderFillExpired); + } + } + private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + const fillMakerTokenAmount = numerator + .mul(target) + .div(denominator) + .round(0); + return fillMakerTokenAmount; + } + constructor(exchangeWrapper: ExchangeWrapper) { + this._exchangeWrapper = exchangeWrapper; + } + public async validateOrderFillableOrThrowAsync( + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + zrxTokenAddress: string, + expectedFillTakerTokenAmount?: BigNumber, + ): Promise { + const orderHash = getOrderHashHex(signedOrder); + const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( + signedOrder.takerTokenAmount, + unavailableTakerTokenAmount, + ); + OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); + if (!_.isUndefined(expectedFillTakerTokenAmount)) { + fillTakerTokenAmount = expectedFillTakerTokenAmount; + } + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + signedOrder.taker, + zrxTokenAddress, + ); + } + public async validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + zrxTokenAddress: string, + ): Promise { + if (fillTakerTokenAmount.eq(0)) { + throw new Error(ExchangeContractErrs.OrderFillAmountZero); + } + const orderHash = getOrderHashHex(signedOrder); + if (!isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) { + throw new Error(OrderError.InvalidSignature); + } + const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); + OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( + signedOrder.takerTokenAmount, + unavailableTakerTokenAmount, + ); + if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) { + throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); + } + OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); + const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) + ? remainingTakerTokenAmount + : fillTakerTokenAmount; + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + filledTakerTokenAmount, + takerAddress, + zrxTokenAddress, + ); + + const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync( + filledTakerTokenAmount, + signedOrder.takerTokenAmount, + signedOrder.makerTokenAmount, + ); + if (wouldRoundingErrorOccur) { + throw new Error(ExchangeContractErrs.OrderFillRoundingError); + } + return filledTakerTokenAmount; + } + public async validateFillOrKillOrderThrowIfInvalidAsync( + exchangeTradeEmulator: ExchangeTransferSimulator, + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + zrxTokenAddress: string, + ): Promise { + const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, + fillTakerTokenAmount, + takerAddress, + zrxTokenAddress, + ); + if (filledTakerTokenAmount !== fillTakerTokenAmount) { + throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount); + } + } +} diff --git a/packages/contract-wrappers/src/utils/utils.ts b/packages/contract-wrappers/src/utils/utils.ts new file mode 100644 index 000000000..af1125632 --- /dev/null +++ b/packages/contract-wrappers/src/utils/utils.ts @@ -0,0 +1,13 @@ +import { BigNumber } from '@0xproject/utils'; + +export const utils = { + spawnSwitchErr(name: string, value: any): Error { + return new Error(`Unexpected switch value: ${value} encountered for ${name}`); + }, + getCurrentUnixTimestampSec(): BigNumber { + return new BigNumber(Date.now() / 1000).round(); + }, + getCurrentUnixTimestampMs(): BigNumber { + return new BigNumber(Date.now()); + }, +}; -- cgit v1.2.3