From 4b3e0383235ca4ca0127f24c2e05543bb45a56bb Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 29 Nov 2017 22:02:43 -0800 Subject: Add contracts to packages, fix most linting errors --- packages/contracts/util/artifacts.ts | 25 ++++ packages/contracts/util/balances.ts | 30 ++++ packages/contracts/util/bignumber_config.ts | 11 ++ packages/contracts/util/constants.ts | 4 + packages/contracts/util/crypto.ts | 38 +++++ packages/contracts/util/exchange_wrapper.ts | 168 ++++++++++++++++++++++ packages/contracts/util/formatters.ts | 74 ++++++++++ packages/contracts/util/multi_sig_wrapper.ts | 34 +++++ packages/contracts/util/order.ts | 109 ++++++++++++++ packages/contracts/util/order_factory.ts | 24 ++++ packages/contracts/util/rpc.ts | 43 ++++++ packages/contracts/util/token_registry_wrapper.ts | 56 ++++++++ packages/contracts/util/types.ts | 119 +++++++++++++++ 13 files changed, 735 insertions(+) create mode 100644 packages/contracts/util/artifacts.ts create mode 100644 packages/contracts/util/balances.ts create mode 100644 packages/contracts/util/bignumber_config.ts create mode 100644 packages/contracts/util/constants.ts create mode 100644 packages/contracts/util/crypto.ts create mode 100644 packages/contracts/util/exchange_wrapper.ts create mode 100644 packages/contracts/util/formatters.ts create mode 100644 packages/contracts/util/multi_sig_wrapper.ts create mode 100644 packages/contracts/util/order.ts create mode 100644 packages/contracts/util/order_factory.ts create mode 100644 packages/contracts/util/rpc.ts create mode 100644 packages/contracts/util/token_registry_wrapper.ts create mode 100644 packages/contracts/util/types.ts (limited to 'packages/contracts/util') diff --git a/packages/contracts/util/artifacts.ts b/packages/contracts/util/artifacts.ts new file mode 100644 index 000000000..8114972d0 --- /dev/null +++ b/packages/contracts/util/artifacts.ts @@ -0,0 +1,25 @@ +export class Artifacts { + public Migrations: any; + public TokenTransferProxy: any; + public TokenRegistry: any; + public MultiSigWalletWithTimeLock: any; + public Exchange: any; + public ZRXToken: any; + public DummyToken: any; + public EtherToken: any; + public MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress: any; + public MaliciousToken: any; + constructor(artifacts: any) { + this.Migrations = artifacts.require('Migrations'); + this.TokenTransferProxy = artifacts.require('TokenTransferProxy'); + this.TokenRegistry = artifacts.require('TokenRegistry'); + this.MultiSigWalletWithTimeLock = artifacts.require('MultiSigWalletWithTimeLock'); + this.Exchange = artifacts.require('Exchange'); + this.ZRXToken = artifacts.require('ZRXToken'); + this.DummyToken = artifacts.require('DummyToken'); + this.EtherToken = artifacts.require('EtherToken'); + this.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress = artifacts.require( + 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress'); + this.MaliciousToken = artifacts.require('MaliciousToken'); + } +} diff --git a/packages/contracts/util/balances.ts b/packages/contracts/util/balances.ts new file mode 100644 index 000000000..ef4abd7bf --- /dev/null +++ b/packages/contracts/util/balances.ts @@ -0,0 +1,30 @@ +import {BigNumber} from 'bignumber.js'; +import * as _ from 'lodash'; + +import {bigNumberConfigs} from './bignumber_config'; +import {BalancesByOwner, ContractInstance} from './types'; + +bigNumberConfigs.configure(); + +export class Balances { + private tokenContractInstances: ContractInstance[]; + private ownerAddresses: string[]; + constructor(tokenContractInstances: ContractInstance[], ownerAddresses: string[]) { + this.tokenContractInstances = tokenContractInstances; + this.ownerAddresses = ownerAddresses; + } + public async getAsync(): Promise { + const balancesByOwner: BalancesByOwner = {}; + for (const tokenContractInstance of this.tokenContractInstances) { + for (const ownerAddress of this.ownerAddresses) { + let balance = await tokenContractInstance.balanceOf(ownerAddress); + balance = new BigNumber(balance); + if (_.isUndefined(balancesByOwner[ownerAddress])) { + balancesByOwner[ownerAddress] = {}; + } + balancesByOwner[ownerAddress][tokenContractInstance.address] = balance; + } + } + return balancesByOwner; + } +} diff --git a/packages/contracts/util/bignumber_config.ts b/packages/contracts/util/bignumber_config.ts new file mode 100644 index 000000000..38f59d341 --- /dev/null +++ b/packages/contracts/util/bignumber_config.ts @@ -0,0 +1,11 @@ +import {BigNumber} from 'bignumber.js'; + +export const bigNumberConfigs = { + configure() { + // By default BigNumber's `toString` method converts to exponential notation if the value has + // more then 20 digits. We want to avoid this behavior, so we set EXPONENTIAL_AT to a high number + BigNumber.config({ + EXPONENTIAL_AT: 1000, + }); + }, +}; diff --git a/packages/contracts/util/constants.ts b/packages/contracts/util/constants.ts new file mode 100644 index 000000000..5beebc68c --- /dev/null +++ b/packages/contracts/util/constants.ts @@ -0,0 +1,4 @@ +export const constants = { + NULL_BYTES: '0x', + INVALID_OPCODE: 'invalid opcode', +}; diff --git a/packages/contracts/util/crypto.ts b/packages/contracts/util/crypto.ts new file mode 100644 index 000000000..e4baee021 --- /dev/null +++ b/packages/contracts/util/crypto.ts @@ -0,0 +1,38 @@ +import {BigNumber} from 'bignumber.js'; +import BN = require('bn.js'); +import ABI = require('ethereumjs-abi'); +import ethUtil = require('ethereumjs-util'); +import * as _ from 'lodash'; + +export const crypto = { + /* + * We convert types from JS to Solidity as follows: + * BigNumber -> uint256 + * number -> uint8 + * string -> string + * boolean -> bool + * valid Ethereum address -> address + */ + solSHA3(args: any[]): Buffer { + const argTypes: string[] = []; + _.each(args, (arg, i) => { + const isNumber = _.isFinite(arg); + if (isNumber) { + argTypes.push('uint8'); + } else if ((arg).isBigNumber) { + argTypes.push('uint256'); + args[i] = new BN(arg.toString(10), 10); + } else if (ethUtil.isValidAddress(arg)) { + argTypes.push('address'); + } else if (_.isString(arg)) { + argTypes.push('string'); + } else if (_.isBoolean(arg)) { + argTypes.push('bool'); + } else { + throw new Error(`Unable to guess arg type: ${arg}`); + } + }); + const hash = ABI.soliditySHA3(argTypes, args); + return hash; + }, +}; diff --git a/packages/contracts/util/exchange_wrapper.ts b/packages/contracts/util/exchange_wrapper.ts new file mode 100644 index 000000000..062ea292b --- /dev/null +++ b/packages/contracts/util/exchange_wrapper.ts @@ -0,0 +1,168 @@ +import {BigNumber} from 'bignumber.js'; +import * as _ from 'lodash'; + +import {formatters} from './formatters'; +import {Order} from './order'; +import {ContractInstance} from './types'; + +export class ExchangeWrapper { + private exchange: ContractInstance; + constructor(exchangeContractInstance: ContractInstance) { + this.exchange = exchangeContractInstance; + } + public async fillOrderAsync(order: Order, from: string, + opts: { + fillTakerTokenAmount?: BigNumber; + shouldThrowOnInsufficientBalanceOrAllowance?: boolean; + } = {}) { + const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; + const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount); + const tx = await this.exchange.fillOrder( + params.orderAddresses, + params.orderValues, + params.fillTakerTokenAmount, + params.shouldThrowOnInsufficientBalanceOrAllowance, + params.v, + params.r, + params.s, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async cancelOrderAsync(order: Order, from: string, + opts: {cancelTakerTokenAmount?: BigNumber} = {}) { + const params = order.createCancel(opts.cancelTakerTokenAmount); + const tx = await this.exchange.cancelOrder( + params.orderAddresses, + params.orderValues, + params.cancelTakerTokenAmount, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async fillOrKillOrderAsync(order: Order, from: string, + opts: {fillTakerTokenAmount?: BigNumber} = {}) { + const shouldThrowOnInsufficientBalanceOrAllowance = true; + const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount); + const tx = await this.exchange.fillOrKillOrder( + params.orderAddresses, + params.orderValues, + params.fillTakerTokenAmount, + params.v, + params.r, + params.s, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async batchFillOrdersAsync(orders: Order[], from: string, + opts: { + fillTakerTokenAmounts?: BigNumber[]; + shouldThrowOnInsufficientBalanceOrAllowance?: boolean; + } = {}) { + const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; + const params = formatters.createBatchFill( + orders, shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmounts); + const tx = await this.exchange.batchFillOrders( + params.orderAddresses, + params.orderValues, + params.fillTakerTokenAmounts, + params.shouldThrowOnInsufficientBalanceOrAllowance, + params.v, + params.r, + params.s, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async batchFillOrKillOrdersAsync(orders: Order[], from: string, + opts: { + fillTakerTokenAmounts?: BigNumber[]; + } = {}) { + const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts); + const tx = await this.exchange.batchFillOrKillOrders( + params.orderAddresses, + params.orderValues, + params.fillTakerTokenAmounts, + params.v, + params.r, + params.s, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async fillOrdersUpToAsync(orders: Order[], from: string, + opts: {fillTakerTokenAmount?: BigNumber; + shouldThrowOnInsufficientBalanceOrAllowance?: boolean; + } = {}) { + const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; + const params = formatters.createFillUpTo(orders, + shouldThrowOnInsufficientBalanceOrAllowance, + opts.fillTakerTokenAmount); + const tx = await this.exchange.fillOrdersUpTo( + params.orderAddresses, + params.orderValues, + params.fillTakerTokenAmount, + params.shouldThrowOnInsufficientBalanceOrAllowance, + params.v, + params.r, + params.s, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async batchCancelOrdersAsync(orders: Order[], from: string, + opts: {cancelTakerTokenAmounts?: BigNumber[]} = {}) { + const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts); + const tx = await this.exchange.batchCancelOrders( + params.orderAddresses, + params.orderValues, + params.cancelTakerTokenAmounts, + {from}, + ); + _.each(tx.logs, log => wrapLogBigNumbers(log)); + return tx; + } + public async getOrderHashAsync(order: Order): Promise { + const shouldThrowOnInsufficientBalanceOrAllowance = false; + const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance); + const orderHash = await this.exchange.getOrderHash(params.orderAddresses, params.orderValues); + return orderHash; + } + public async isValidSignatureAsync(order: Order): Promise { + const isValidSignature = await this.exchange.isValidSignature( + order.params.maker, + order.params.orderHashHex, + order.params.v, + order.params.r, + order.params.s, + ); + return isValidSignature; + } + public async isRoundingErrorAsync(numerator: BigNumber, denominator: BigNumber, + target: BigNumber): Promise { + const isRoundingError = await this.exchange.isRoundingError(numerator, denominator, target); + return isRoundingError; + } + public async getPartialAmountAsync(numerator: BigNumber, denominator: BigNumber, + target: BigNumber): Promise { + const partialAmount = new BigNumber(await this.exchange.getPartialAmount(numerator, denominator, target)); + return partialAmount; + } +} + +function wrapLogBigNumbers(log: any): any { + const argNames = _.keys(log.args); + for (const argName of argNames) { + const isWeb3BigNumber = _.startsWith(log.args[argName].constructor.toString(), 'function BigNumber('); + if (isWeb3BigNumber) { + log.args[argName] = new BigNumber(log.args[argName]); + } + } +} diff --git a/packages/contracts/util/formatters.ts b/packages/contracts/util/formatters.ts new file mode 100644 index 000000000..cda548617 --- /dev/null +++ b/packages/contracts/util/formatters.ts @@ -0,0 +1,74 @@ +import {BigNumber} from 'bignumber.js'; +import * as _ from 'lodash'; + +import {Order} from './order'; +import {BatchCancelOrders, BatchFillOrders, FillOrdersUpTo} from './types'; + +export const formatters = { + createBatchFill(orders: Order[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + fillTakerTokenAmounts: BigNumber[] = []) { + const batchFill: BatchFillOrders = { + orderAddresses: [], + orderValues: [], + fillTakerTokenAmounts, + shouldThrowOnInsufficientBalanceOrAllowance, + v: [], + r: [], + s: [], + }; + _.forEach(orders, order => { + batchFill.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, + order.params.takerToken, order.params.feeRecipient]); + batchFill.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, order.params.makerFee, + order.params.takerFee, order.params.expirationTimestampInSec, order.params.salt]); + batchFill.v.push(order.params.v); + batchFill.r.push(order.params.r); + batchFill.s.push(order.params.s); + if (fillTakerTokenAmounts.length < orders.length) { + batchFill.fillTakerTokenAmounts.push(order.params.takerTokenAmount); + } + }); + return batchFill; + }, + createFillUpTo(orders: Order[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + fillTakerTokenAmount: BigNumber) { + const fillUpTo: FillOrdersUpTo = { + orderAddresses: [], + orderValues: [], + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + v: [], + r: [], + s: [], + }; + orders.forEach(order => { + fillUpTo.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, + order.params.takerToken, order.params.feeRecipient]); + fillUpTo.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, order.params.makerFee, + order.params.takerFee, order.params.expirationTimestampInSec, order.params.salt]); + fillUpTo.v.push(order.params.v); + fillUpTo.r.push(order.params.r); + fillUpTo.s.push(order.params.s); + }); + return fillUpTo; + }, + createBatchCancel(orders: Order[], cancelTakerTokenAmounts: BigNumber[] = []) { + const batchCancel: BatchCancelOrders = { + orderAddresses: [], + orderValues: [], + cancelTakerTokenAmounts, + }; + orders.forEach(order => { + batchCancel.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, + order.params.takerToken, order.params.feeRecipient]); + batchCancel.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, order.params.makerFee, + order.params.takerFee, order.params.expirationTimestampInSec, order.params.salt]); + if (cancelTakerTokenAmounts.length < orders.length) { + batchCancel.cancelTakerTokenAmounts.push(order.params.takerTokenAmount); + } + }); + return batchCancel; + }, +}; diff --git a/packages/contracts/util/multi_sig_wrapper.ts b/packages/contracts/util/multi_sig_wrapper.ts new file mode 100644 index 000000000..7c13dae97 --- /dev/null +++ b/packages/contracts/util/multi_sig_wrapper.ts @@ -0,0 +1,34 @@ +import ABI = require('ethereumjs-abi'); +import ethUtil = require('ethereumjs-util'); +import * as _ from 'lodash'; +import * as Web3 from 'web3'; + +import {ContractInstance, TransactionDataParams} from './types'; + +export class MultiSigWrapper { + private multiSig: ContractInstance; + constructor(multiSigContractInstance: ContractInstance) { + this.multiSig = multiSigContractInstance; + } + public async submitTransactionAsync(destination: string, from: string, + dataParams: TransactionDataParams, + value: number = 0) { + const {name, abi, args = []} = dataParams; + const encoded = this.encodeFnArgs(name, abi, args); + return this.multiSig.submitTransaction(destination, value, encoded, {from}); + } + public encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) { + const abiEntity = _.find(abi, {name}) as Web3.MethodAbi; + if (_.isUndefined(abiEntity)) { + throw new Error(`Did not find abi entry for name: ${name}`); + } + const types = _.map(abiEntity.inputs, input => input.type); + const funcSig = ethUtil.bufferToHex(ABI.methodID(name, types)); + const argsData = _.map(args, arg => { + const target = _.isBoolean(arg) ? +arg : arg; + const targetBuff = ethUtil.toBuffer(target); + return ethUtil.setLengthLeft(targetBuff, 32).toString('hex'); + }); + return funcSig + argsData.join(''); + } +} diff --git a/packages/contracts/util/order.ts b/packages/contracts/util/order.ts new file mode 100644 index 000000000..635999348 --- /dev/null +++ b/packages/contracts/util/order.ts @@ -0,0 +1,109 @@ +import {BigNumber} from 'bignumber.js'; +import promisify = require('es6-promisify'); +import ethUtil = require('ethereumjs-util'); +import * as _ from 'lodash'; +import Web3 = require('web3'); + +import {crypto} from './crypto'; +import {OrderParams} from './types'; + +// In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle +// with type `any` to a variable of type `Web3`. +const web3: Web3 = (global as any).web3; + +export class Order { + public params: OrderParams; + constructor(params: OrderParams) { + this.params = params; + } + public isValidSignature() { + const {v, r, s} = this.params; + if (_.isUndefined(v) || _.isUndefined(r) || _.isUndefined(s)) { + throw new Error('Cannot call isValidSignature on unsigned order'); + } + const orderHash = this.getOrderHash(); + const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash)); + try { + const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s)); + const recoveredAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); + return recoveredAddress === this.params.maker; + } catch (err) { + return false; + } + } + public async signAsync() { + const orderHash = this.getOrderHash(); + const signature = await promisify(web3.eth.sign)(this.params.maker, orderHash); + const {v, r, s} = ethUtil.fromRpcSig(signature); + this.params = _.assign(this.params, { + orderHashHex: orderHash, + v, + r: ethUtil.bufferToHex(r), + s: ethUtil.bufferToHex(s), + }); + } + public createFill(shouldThrowOnInsufficientBalanceOrAllowance?: boolean, fillTakerTokenAmount?: BigNumber) { + const fill = { + orderAddresses: [ + this.params.maker, + this.params.taker, + this.params.makerToken, + this.params.takerToken, + this.params.feeRecipient, + ], + orderValues: [ + this.params.makerTokenAmount, + this.params.takerTokenAmount, + this.params.makerFee, + this.params.takerFee, + this.params.expirationTimestampInSec, + this.params.salt, + ], + fillTakerTokenAmount: fillTakerTokenAmount || this.params.takerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance: !!shouldThrowOnInsufficientBalanceOrAllowance, + v: this.params.v, + r: this.params.r, + s: this.params.s, + }; + return fill; + } + public createCancel(cancelTakerTokenAmount?: BigNumber) { + const cancel = { + orderAddresses: [ + this.params.maker, + this.params.taker, + this.params.makerToken, + this.params.takerToken, + this.params.feeRecipient, + ], + orderValues: [ + this.params.makerTokenAmount, + this.params.takerTokenAmount, + this.params.makerFee, + this.params.takerFee, + this.params.expirationTimestampInSec, + this.params.salt, + ], + cancelTakerTokenAmount: cancelTakerTokenAmount || this.params.takerTokenAmount, + }; + return cancel; + } + private getOrderHash(): string { + const orderHash = crypto.solSHA3([ + this.params.exchangeContractAddress, + this.params.maker, + this.params.taker, + this.params.makerToken, + this.params.takerToken, + this.params.feeRecipient, + this.params.makerTokenAmount, + this.params.takerTokenAmount, + this.params.makerFee, + this.params.takerFee, + this.params.expirationTimestampInSec, + this.params.salt, + ]); + const orderHashHex = ethUtil.bufferToHex(orderHash); + return orderHashHex; + } +} diff --git a/packages/contracts/util/order_factory.ts b/packages/contracts/util/order_factory.ts new file mode 100644 index 000000000..cdce7d18a --- /dev/null +++ b/packages/contracts/util/order_factory.ts @@ -0,0 +1,24 @@ +import {ZeroEx} from '0x.js'; +import {BigNumber} from 'bignumber.js'; +import * as _ from 'lodash'; + +import {Order} from './order'; +import {DefaultOrderParams, OptionalOrderParams, OrderParams} from './types'; + +export class OrderFactory { + private defaultOrderParams: DefaultOrderParams; + constructor(defaultOrderParams: DefaultOrderParams) { + this.defaultOrderParams = defaultOrderParams; + } + public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) { + const randomExpiration = new BigNumber(Math.floor((Date.now() + (Math.random() * 100000000000)) / 1000)); + const orderParams: OrderParams = _.assign({}, { + expirationTimestampInSec: randomExpiration, + salt: ZeroEx.generatePseudoRandomSalt(), + taker: ZeroEx.NULL_ADDRESS, + }, this.defaultOrderParams, customOrderParams); + const order = new Order(orderParams); + await order.signAsync(); + return order; + } +} diff --git a/packages/contracts/util/rpc.ts b/packages/contracts/util/rpc.ts new file mode 100644 index 000000000..37643874c --- /dev/null +++ b/packages/contracts/util/rpc.ts @@ -0,0 +1,43 @@ +import 'isomorphic-fetch'; + +import * as truffleConf from '../truffle.js'; + +export class RPC { + private host: string; + private port: number; + private id: number; + constructor() { + this.host = truffleConf.networks.development.host; + this.port = truffleConf.networks.development.port; + this.id = 0; + } + public async increaseTimeAsync(time: number) { + const method = 'evm_increaseTime'; + const params = [time]; + const payload = this.toPayload(method, params); + return this.sendAsync(payload); + } + public async mineBlockAsync() { + const method = 'evm_mine'; + const payload = this.toPayload(method); + return this.sendAsync(payload); + } + private toPayload(method: string, params: any[] = []) { + const payload = JSON.stringify({ + id: this.id, + method, + params, + }); + this.id++; + return payload; + } + private async sendAsync(payload: string): Promise { + const opts = { + method: 'POST', + body: payload, + }; + const response = await fetch(`http://${this.host}:${this.port}`, opts); + const responsePayload = await response.json(); + return responsePayload; + } +} diff --git a/packages/contracts/util/token_registry_wrapper.ts b/packages/contracts/util/token_registry_wrapper.ts new file mode 100644 index 000000000..5065a1802 --- /dev/null +++ b/packages/contracts/util/token_registry_wrapper.ts @@ -0,0 +1,56 @@ +import {ContractInstance, Token} from './types'; + +export class TokenRegWrapper { + private tokenReg: ContractInstance; + constructor(tokenRegContractInstance: ContractInstance) { + this.tokenReg = tokenRegContractInstance; + } + public addTokenAsync(token: Token, from: string) { + const tx = this.tokenReg.addToken( + token.address, + token.name, + token.symbol, + token.decimals, + token.ipfsHash, + token.swarmHash, + {from}, + ); + return tx; + } + public async getTokenMetaDataAsync(tokenAddress: string) { + const data = await this.tokenReg.getTokenMetaData(tokenAddress); + const token: Token = { + address: data[0], + name: data[1], + symbol: data[2], + decimals: data[3].toNumber(), + ipfsHash: data[4], + swarmHash: data[5], + }; + return token; + } + public async getTokenByNameAsync(tokenName: string) { + const data = await this.tokenReg.getTokenByName(tokenName); + const token: Token = { + address: data[0], + name: data[1], + symbol: data[2], + decimals: data[3].toNumber(), + ipfsHash: data[4], + swarmHash: data[5], + }; + return token; + } + public async getTokenBySymbolAsync(tokenSymbol: string) { + const data = await this.tokenReg.getTokenBySymbol(tokenSymbol); + const token: Token = { + address: data[0], + name: data[1], + symbol: data[2], + decimals: data[3].toNumber(), + ipfsHash: data[4], + swarmHash: data[5], + }; + return token; + } +} diff --git a/packages/contracts/util/types.ts b/packages/contracts/util/types.ts new file mode 100644 index 000000000..2e16fac7a --- /dev/null +++ b/packages/contracts/util/types.ts @@ -0,0 +1,119 @@ +import {BigNumber} from 'bignumber.js'; +import * as Web3 from 'web3'; + +export interface BalancesByOwner { + [ownerAddress: string]: { + [tokenAddress: string]: BigNumber; + }; +} + +export interface BatchFillOrders { + orderAddresses: string[][]; + orderValues: BigNumber[][]; + fillTakerTokenAmounts: BigNumber[]; + shouldThrowOnInsufficientBalanceOrAllowance: boolean; + v: number[]; + r: string[]; + s: string[]; +} + +export interface FillOrdersUpTo { + orderAddresses: string[][]; + orderValues: BigNumber[][]; + fillTakerTokenAmount: BigNumber; + shouldThrowOnInsufficientBalanceOrAllowance: boolean; + v: number[]; + r: string[]; + s: string[]; +} + +export interface BatchCancelOrders { + orderAddresses: string[][]; + orderValues: BigNumber[][]; + cancelTakerTokenAmounts: BigNumber[]; +} + +export interface DefaultOrderParams { + exchangeContractAddress: string; + maker: string; + feeRecipient: string; + makerToken: string; + takerToken: string; + makerTokenAmount: BigNumber; + takerTokenAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; +} + +export interface OptionalOrderParams { + exchangeContractAddress?: string; + maker?: string; + taker?: string; + feeRecipient?: string; + makerToken?: string; + takerToken?: string; + makerTokenAmount?: BigNumber; + takerTokenAmount?: BigNumber; + makerFee?: BigNumber; + takerFee?: BigNumber; + expirationTimestampInSec?: BigNumber; +} + +export interface OrderParams { + exchangeContractAddress: string; + maker: string; + taker: string; + feeRecipient: string; + makerToken: string; + takerToken: string; + makerTokenAmount: BigNumber; + takerTokenAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimestampInSec: BigNumber; + salt: BigNumber; + orderHashHex?: string; + v?: number; + r?: string; + s?: string; +} + +export interface TransactionDataParams { + name: string; + abi: Web3.AbiDefinition[]; + args: any[]; +} + +export interface Token { + address?: string; + name: string; + symbol: string; + decimals: number; + ipfsHash: string; + swarmHash: string; +} + +export interface MultiSigConfig { + owners: string[]; + confirmationsRequired: number; + secondsRequired: number; +} + +export interface MultiSigConfigByNetwork { + [networkName: string]: MultiSigConfig; +} + +export interface TokenInfoByNetwork { + development: Token[]; + live: Token[]; +} + +// Named type aliases to improve readability +export type ContractInstance = any; + +export enum ExchangeContractErrs { + ERROR_ORDER_EXPIRED, + ERROR_ORDER_FULLY_FILLED_OR_CANCELLED, + ERROR_ROUNDING_ERROR_TOO_LARGE, + ERROR_INSUFFICIENT_BALANCE_OR_ALLOWANCE, +} -- cgit v1.2.3