From 919585cd7972bae1667f67c9fa034251f27b14a8 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 29 May 2017 23:51:27 +0200 Subject: Add TokenRegistryWrapper and getTokensAsync method --- src/0x.js.ts | 3 +++ src/contract_wrappers/token_registry_wrapper.ts | 33 +++++++++++++++++++++++++ src/types.ts | 13 ++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/contract_wrappers/token_registry_wrapper.ts diff --git a/src/0x.js.ts b/src/0x.js.ts index d708a8db6..7e48bc0a5 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -11,6 +11,7 @@ import {assert} from './utils/assert'; import findVersions = require('find-versions'); import compareVersions = require('compare-versions'); import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper'; +import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper'; import {ecSignatureSchema} from './schemas/ec_signature_schema'; import {SolidityTypes, ECSignature, ZeroExError} from './types'; @@ -19,6 +20,7 @@ const MAX_DIGITS_IN_UNSIGNED_256_INT = 78; export class ZeroEx { public web3Wrapper: Web3Wrapper; public exchange: ExchangeWrapper; + public tokenRegistry: TokenRegistryWrapper; /** * Computes the orderHash given the order parameters and returns it as a hex encoded string. */ @@ -132,6 +134,7 @@ export class ZeroEx { constructor(web3: Web3) { this.web3Wrapper = new Web3Wrapper(web3); this.exchange = new ExchangeWrapper(this.web3Wrapper); + this.tokenRegistry = new TokenRegistryWrapper(this.web3Wrapper); } /** * Signs an orderHash and returns it's elliptic curve signature diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts new file mode 100644 index 000000000..4d6eacb51 --- /dev/null +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -0,0 +1,33 @@ +import * as _ from 'lodash'; +import {Web3Wrapper} from '../web3_wrapper'; +import {ZeroExError, Token, TokenRegistryContract} from '../types'; +import {assert} from '../utils/assert'; +import {ContractWrapper} from './contract_wrapper'; +import * as TokenRegistryArtifacts from '../artifacts/TokenRegistry.json'; + +export class TokenRegistryWrapper extends ContractWrapper { + constructor(web3Wrapper: Web3Wrapper) { + super(web3Wrapper); + } + public async getTokensAsync(): Promise { + const contractInstance = await this.instantiateContractIfExistsAsync((TokenRegistryArtifacts as any)); + const tokenRegistryContract = contractInstance as TokenRegistryContract; + + const addresses = await tokenRegistryContract.getTokenAddresses.call(); + const tokenMetadataPromises: Array> = _.map( + addresses, + (address: string) => (tokenRegistryContract.getTokenMetaData.call(address)), + ); + const tokensMetadata = await Promise.all(tokenMetadataPromises); + const tokens = _.map(tokensMetadata, metadata => { + return { + address: metadata[0], + name: metadata[1], + symbol: metadata[2], + url: metadata[3], + decimals: metadata[4].toNumber(), + }; + }); + return tokens; + } +} diff --git a/src/types.ts b/src/types.ts index 3bed01547..273389480 100644 --- a/src/types.ts +++ b/src/types.ts @@ -30,8 +30,21 @@ export interface ExchangeContract { isValidSignature: any; } +export interface TokenRegistryContract { + getTokenMetaData: any; + getTokenAddresses: any; +} + export const SolidityTypes = strEnum([ 'address', 'uint256', ]); export type SolidityTypes = keyof typeof SolidityTypes; + +export interface Token { + name: string; + address: string; + symbol: string; + decimals: number; + url: string; +}; -- cgit v1.2.3 From f3d5690d56c3e4c7243f72049c98cfde799413af Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 29 May 2017 23:52:10 +0200 Subject: Add tests for getTokensAsync including schema validation --- src/schemas/token_schema.ts | 12 +++++++++++ src/utils/schema_validator.ts | 2 ++ test/token_registry_wrapper_test.ts | 43 +++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/schemas/token_schema.ts create mode 100644 test/token_registry_wrapper_test.ts diff --git a/src/schemas/token_schema.ts b/src/schemas/token_schema.ts new file mode 100644 index 000000000..01702af68 --- /dev/null +++ b/src/schemas/token_schema.ts @@ -0,0 +1,12 @@ +export const tokenSchema = { + id: '/token', + properties: { + name: {type: 'string'}, + symbol: {type: 'string'}, + decimals: {type: 'number'}, + address: {type: 'string'}, + url: {type: 'string'}, + }, + required: ['name', 'symbol', 'decimals', 'address', 'url'], + type: 'object', +}; diff --git a/src/utils/schema_validator.ts b/src/utils/schema_validator.ts index 61f4c09c8..8132f7414 100644 --- a/src/utils/schema_validator.ts +++ b/src/utils/schema_validator.ts @@ -1,5 +1,6 @@ import {Validator, ValidatorResult} from 'jsonschema'; import {ecSignatureSchema, ecSignatureParameter} from '../schemas/ec_signature_schema'; +import {tokenSchema} from '../schemas/token_schema'; export class SchemaValidator { private validator: Validator; @@ -7,6 +8,7 @@ export class SchemaValidator { this.validator = new Validator(); this.validator.addSchema(ecSignatureParameter, ecSignatureParameter.id); this.validator.addSchema(ecSignatureSchema, ecSignatureSchema.id); + this.validator.addSchema(tokenSchema, tokenSchema.id); } public validate(instance: object, schema: Schema): ValidatorResult { return this.validator.validate(instance, schema); diff --git a/test/token_registry_wrapper_test.ts b/test/token_registry_wrapper_test.ts new file mode 100644 index 000000000..cd435c48c --- /dev/null +++ b/test/token_registry_wrapper_test.ts @@ -0,0 +1,43 @@ +import * as _ from 'lodash'; +import 'mocha'; +import * as chai from 'chai'; +import chaiAsPromised = require('chai-as-promised'); +import * as Web3 from 'web3'; +import {web3Factory} from './utils/web3_factory'; +import {ZeroEx} from '../src/0x.js'; +import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; +import {Token} from '../src/types'; +import {SchemaValidator} from '../src/utils/schema_validator'; +import {tokenSchema} from '../src/schemas/token_schema'; + +const expect = chai.expect; +chai.use(chaiAsPromised); +const blockchainLifecycle = new BlockchainLifecycle(); + +const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7; + +describe('TokenRegistryWrapper', () => { + let zeroEx: ZeroEx; + before(async () => { + const web3 = web3Factory.create(); + zeroEx = new ZeroEx(web3); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('#getTokensAsync', () => { + it('should return all the tokens added to the tokenRegistry during the migration', async () => { + const tokens = await zeroEx.tokenRegistry.getTokensAsync(); + expect(tokens.length).to.be.equal(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); + + const schemaValidator = new SchemaValidator(); + _.each(tokens, token => { + const validationResult = schemaValidator.validate(token, tokenSchema); + expect(validationResult.errors.length).to.be.equal(0); + }); + }); + }); +}); -- cgit v1.2.3 From 5bfc3f8976be50ca5fc6d7a2518e94e48b216af4 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 30 May 2017 10:19:29 +0200 Subject: remove unused import --- src/contract_wrappers/token_registry_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index 4d6eacb51..431b0303d 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -1,6 +1,6 @@ import * as _ from 'lodash'; import {Web3Wrapper} from '../web3_wrapper'; -import {ZeroExError, Token, TokenRegistryContract} from '../types'; +import {Token, TokenRegistryContract} from '../types'; import {assert} from '../utils/assert'; import {ContractWrapper} from './contract_wrapper'; import * as TokenRegistryArtifacts from '../artifacts/TokenRegistry.json'; -- cgit v1.2.3 From 220f92541545851abda885df196be790e08fe040 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 30 May 2017 10:21:48 +0200 Subject: Fix the empty code regex --- src/web3_wrapper.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/web3_wrapper.ts b/src/web3_wrapper.ts index 97d04db8c..a915a89e8 100644 --- a/src/web3_wrapper.ts +++ b/src/web3_wrapper.ts @@ -49,10 +49,9 @@ export class Web3Wrapper { } public async doesContractExistAtAddressAsync(address: string): Promise { const code = await promisify(this.web3.eth.getCode)(address); - // Regex matches 0x0, 0x00, 0x in order to accomodate poorly implemented clients - const zeroHexAddressRegex = /^0x0*$/i; - const didFindCode = _.isNull(code.match(zeroHexAddressRegex)); - return didFindCode; + // Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients + const codeIsEmpty = /^0x0{0,40}$/i.test(code); + return !codeIsEmpty; } public async signTransactionAsync(address: string, message: string): Promise { const signData = await promisify(this.web3.eth.sign)(address, message); -- cgit v1.2.3 From f2cd368a491fd868b063e4023bba1dc2b395b387 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 30 May 2017 10:42:39 +0200 Subject: Add TokenMetadata type --- src/contract_wrappers/token_registry_wrapper.ts | 4 ++-- src/types.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index 431b0303d..8dd79171e 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -1,6 +1,6 @@ import * as _ from 'lodash'; import {Web3Wrapper} from '../web3_wrapper'; -import {Token, TokenRegistryContract} from '../types'; +import {Token, TokenRegistryContract, TokenMetadata} from '../types'; import {assert} from '../utils/assert'; import {ContractWrapper} from './contract_wrapper'; import * as TokenRegistryArtifacts from '../artifacts/TokenRegistry.json'; @@ -14,7 +14,7 @@ export class TokenRegistryWrapper extends ContractWrapper { const tokenRegistryContract = contractInstance as TokenRegistryContract; const addresses = await tokenRegistryContract.getTokenAddresses.call(); - const tokenMetadataPromises: Array> = _.map( + const tokenMetadataPromises: Array> = _.map( addresses, (address: string) => (tokenRegistryContract.getTokenMetaData.call(address)), ); diff --git a/src/types.ts b/src/types.ts index 273389480..57ffcd44b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,6 +41,9 @@ export const SolidityTypes = strEnum([ ]); export type SolidityTypes = keyof typeof SolidityTypes; +// [address, name, symbol, projectUrl, decimals, ipfsHash, swarmHash] +export type TokenMetadata = [string, string, string, string, BigNumber.BigNumber, string, string]; + export interface Token { name: string; address: string; -- cgit v1.2.3 From 1e69d2d1e1d27b5438d9064bd9a41cd53014770f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 30 May 2017 10:48:34 +0200 Subject: Improve type definitions --- src/types.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/types.ts b/src/types.ts index 57ffcd44b..6fce95706 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,8 +31,12 @@ export interface ExchangeContract { } export interface TokenRegistryContract { - getTokenMetaData: any; - getTokenAddresses: any; + getTokenMetaData: { + call: (address: string) => Promise; + }; + getTokenAddresses: { + call: () => Promise; + }; } export const SolidityTypes = strEnum([ -- cgit v1.2.3 From 4d63a4d02a68974df75c9cae85d43c0ba628c740 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 30 May 2017 10:49:34 +0200 Subject: use to.have.lengthOf --- test/token_registry_wrapper_test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/token_registry_wrapper_test.ts b/test/token_registry_wrapper_test.ts index cd435c48c..c91555d8b 100644 --- a/test/token_registry_wrapper_test.ts +++ b/test/token_registry_wrapper_test.ts @@ -31,12 +31,12 @@ describe('TokenRegistryWrapper', () => { describe('#getTokensAsync', () => { it('should return all the tokens added to the tokenRegistry during the migration', async () => { const tokens = await zeroEx.tokenRegistry.getTokensAsync(); - expect(tokens.length).to.be.equal(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); + expect(tokens).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); const schemaValidator = new SchemaValidator(); _.each(tokens, token => { const validationResult = schemaValidator.validate(token, tokenSchema); - expect(validationResult.errors.length).to.be.equal(0); + expect(validationResult.errors).to.have.lengthOf(0); }); }); }); -- cgit v1.2.3