From 82ef8b19f01644dee14894e8dc4ec5ef33e922e9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 23 Aug 2017 20:09:09 +0200 Subject: [PATCH 1/8] Add zeroEx.tokenRegistry.getTokenAddressesAsync() --- src/contract_wrappers/token_registry_wrapper.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index 58c191ea5d..ddfbc35ae9 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -21,7 +21,7 @@ export class TokenRegistryWrapper extends ContractWrapper { public async getTokensAsync(): Promise { const tokenRegistryContract = await this._getTokenRegistryContractAsync(); - const addresses = await tokenRegistryContract.getTokenAddresses.call(); + const addresses = await this.getTokenAddressesAsync(); const tokenPromises: Array> = _.map( addresses, (address: string) => (this.getTokenIfExistsAsync(address)), @@ -29,6 +29,15 @@ export class TokenRegistryWrapper extends ContractWrapper { 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.call(); + return addresses; + } /** * 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. From 0d7b75801a4594ebbf2d712441d04418473a51f5 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 23 Aug 2017 20:12:58 +0200 Subject: [PATCH 2/8] Add test for getTokenAddressesAsync --- test/token_registry_wrapper_test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/token_registry_wrapper_test.ts b/test/token_registry_wrapper_test.ts index 6b5640c6c1..2b08732453 100644 --- a/test/token_registry_wrapper_test.ts +++ b/test/token_registry_wrapper_test.ts @@ -7,6 +7,7 @@ import {ZeroEx} from '../src'; import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; import {SchemaValidator} from '../src/utils/schema_validator'; import {tokenSchema} from '../src/schemas/token_schema'; +import {addressSchema} from '../src/schemas/basic_type_schemas'; chaiSetup.configure(); const expect = chai.expect; @@ -38,6 +39,19 @@ describe('TokenRegistryWrapper', () => { }); }); }); + describe('#getTokenAddressesAsync', () => { + it('should return all the token addresses added to the tokenRegistry during the migration', async () => { + const tokenAddresses = await zeroEx.tokenRegistry.getTokenAddressesAsync(); + expect(tokenAddresses).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); + + const schemaValidator = new SchemaValidator(); + _.each(tokenAddresses, tokenAddress => { + const validationResult = schemaValidator.validate(tokenAddress, addressSchema); + expect(validationResult.errors).to.have.lengthOf(0); + expect(tokenAddress).to.not.be.equal(ZeroEx.NULL_ADDRESS); + }); + }); + }); describe('#getTokenIfExistsAsync', () => { it('should return the token added to the tokenRegistry during the migration', async () => { const tokens = await zeroEx.tokenRegistry.getTokensAsync(); From e4f5b9cdb3021a7af1fa97c2ef0233bdf59af62c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 23 Aug 2017 20:28:48 +0200 Subject: [PATCH 3/8] Add all public tokenRegistry functions --- .../token_registry_wrapper.ts | 38 +++++++++++++++++++ src/types.ts | 12 ++++++ 2 files changed, 50 insertions(+) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index ddfbc35ae9..207259fcdf 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -47,6 +47,44 @@ export class TokenRegistryWrapper extends ContractWrapper { const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenMetaData.call(address); + const token = this._getTokenByMetadata(metadata); + return token; + } + public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise { + assert.isString('symbol', symbol); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.call(symbol); + if (addressIfExists === constants.NULL_ADDRESS) { + return undefined; + } else { + return addressIfExists; + } + } + public async getTokenAddressByNameIfExistsAsync(symbol: string): Promise { + assert.isString('name', name); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const addressIfExists = await tokenRegistryContract.getTokenAddressByName.call(name); + if (addressIfExists === constants.NULL_ADDRESS) { + return undefined; + } else { + return addressIfExists; + } + } + public async getTokenBySymbolIfExistsAsync(symbol: string): Promise { + assert.isString('symbol', symbol); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const metadata = await tokenRegistryContract.getTokenBySymbol.call(symbol); + const token = this._getTokenByMetadata(metadata); + return token; + } + public async getTokenByNameIfExistsAsync(name: string): Promise { + assert.isString('name', name); + const tokenRegistryContract = await this._getTokenRegistryContractAsync(); + const metadata = await tokenRegistryContract.getTokenByName.call(name); + const token = this._getTokenByMetadata(metadata); + return token; + } + private _getTokenByMetadata(metadata: TokenMetadata): Token|undefined { if (metadata[0] === constants.NULL_ADDRESS) { return undefined; } diff --git a/src/types.ts b/src/types.ts index 5ba85a7d53..71227647bd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -145,6 +145,18 @@ export interface TokenRegistryContract extends ContractInstance { getTokenAddresses: { call: () => Promise; }; + getTokenAddressBySymbol: { + call: (symbol: string) => Promise; + }; + getTokenAddressByName: { + call: (name: string) => Promise; + }; + getTokenBySymbol: { + call: (symbol: string) => Promise; + }; + getTokenByName: { + call: (name: string) => Promise; + }; } export interface EtherTokenContract extends ContractInstance { From a41ea299e58d594f908736ba50fafd31310db5f7 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 23 Aug 2017 20:44:41 +0200 Subject: [PATCH 4/8] Add tests for tokenRegistry public getters --- .../token_registry_wrapper.ts | 2 +- test/token_registry_wrapper_test.ts | 60 ++++++++++++++++++- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index 207259fcdf..7a88d329de 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -60,7 +60,7 @@ export class TokenRegistryWrapper extends ContractWrapper { return addressIfExists; } } - public async getTokenAddressByNameIfExistsAsync(symbol: string): Promise { + public async getTokenAddressByNameIfExistsAsync(name: string): Promise { assert.isString('name', name); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const addressIfExists = await tokenRegistryContract.getTokenAddressByName.call(name); diff --git a/test/token_registry_wrapper_test.ts b/test/token_registry_wrapper_test.ts index 2b08732453..18f2f25413 100644 --- a/test/token_registry_wrapper_test.ts +++ b/test/token_registry_wrapper_test.ts @@ -3,7 +3,7 @@ import 'mocha'; import * as chai from 'chai'; import {chaiSetup} from './utils/chai_setup'; import {web3Factory} from './utils/web3_factory'; -import {ZeroEx} from '../src'; +import {ZeroEx, Token} from '../src'; import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; import {SchemaValidator} from '../src/utils/schema_validator'; import {tokenSchema} from '../src/schemas/token_schema'; @@ -17,9 +17,25 @@ const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7; describe('TokenRegistryWrapper', () => { let zeroEx: ZeroEx; + let tokens: Token[]; + const tokenAddressBySymbol: {[symbol: string]: string} = {}; + const tokenAddressByName: {[symbol: string]: string} = {}; + const tokenBySymbol: {[symbol: string]: Token} = {}; + const tokenByName: {[symbol: string]: Token} = {}; + const registeredSymbol = 'ZRX'; + const registeredName = '0x Protocol Token'; + const unregisteredSymbol = 'FUCK'; + const unregisteredName = 'FUCKtoken'; before(async () => { const web3 = web3Factory.create(); zeroEx = new ZeroEx(web3.currentProvider); + tokens = await zeroEx.tokenRegistry.getTokensAsync(); + _.map(tokens, token => { + tokenAddressBySymbol[token.symbol] = token.address; + tokenAddressByName[token.name] = token.address; + tokenBySymbol[token.symbol] = token; + tokenByName[token.name] = token; + }); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -29,7 +45,6 @@ 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).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION); const schemaValidator = new SchemaValidator(); @@ -52,9 +67,48 @@ describe('TokenRegistryWrapper', () => { }); }); }); + describe('#getTokenAddressBySymbol', () => { + it('should return correct address for a token in the registry', async () => { + const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync(registeredSymbol); + expect(tokenAddress).to.be.equal(tokenAddressBySymbol[registeredSymbol]); + }); + it('should return undefined for a token out of registry', async () => { + const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync(unregisteredSymbol); + expect(tokenAddress).to.be.undefined(); + }); + }); + describe('#getTokenAddressByName', () => { + it('should return correct address for a token in the registry', async () => { + const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync(registeredName); + expect(tokenAddress).to.be.equal(tokenAddressByName[registeredName]); + }); + it('should return undefined for a token out of registry', async () => { + const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync(unregisteredName); + expect(tokenAddress).to.be.undefined(); + }); + }); + describe('#getTokenBySymbol', () => { + it('should return correct token for a token in the registry', async () => { + const token = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync(registeredSymbol); + expect(token).to.be.deep.equal(tokenBySymbol[registeredSymbol]); + }); + it('should return undefined for a token out of registry', async () => { + const token = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync(unregisteredSymbol); + expect(token).to.be.undefined(); + }); + }); + describe('#getTokenByName', () => { + it('should return correct token for a token in the registry', async () => { + const token = await zeroEx.tokenRegistry.getTokenByNameIfExistsAsync(registeredName); + expect(token).to.be.deep.equal(tokenByName[registeredName]); + }); + it('should return undefined for a token out of registry', async () => { + const token = await zeroEx.tokenRegistry.getTokenByNameIfExistsAsync(unregisteredName); + expect(token).to.be.undefined(); + }); + }); describe('#getTokenIfExistsAsync', () => { it('should return the token added to the tokenRegistry during the migration', async () => { - const tokens = await zeroEx.tokenRegistry.getTokensAsync(); const aToken = tokens[0]; const token = await zeroEx.tokenRegistry.getTokenIfExistsAsync(aToken.address); From 846eec62698af06549f83aae5e661f67291bb329 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 23 Aug 2017 20:48:39 +0200 Subject: [PATCH 5/8] Document changes in a CHANGELOG --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5fef398c6..d8f3b8e7eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,17 @@ # CHANGELOG -v0.10.0 - _TBD_ +v0.10.0 - _Aug 24, 2017_ ------------------------ * Added `zeroEx.exchange.validateFillOrderThrowIfInvalidAsync` (#128) * Added `zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync` (#128) * Added `zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync` (#128) * Added `zeroEx.exchange.isRoundingErrorAsync` (#128) * Added `zeroEx.proxy.getContractAddressAsync` (#130) + * Added `zeroEx.tokenRegistry.getTokenAddressesAsync` (#132) + * Added `zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync` (#132) + * Added `zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync` (#132) + * Added `zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync` (#132) + * Added `zeroEx.tokenRegistry.getTokenByNameIfExistsAsync` (#132) * Added clear error message when checksummed address is passed to a public method (#124) * Fixes the description of `shouldThrowOnInsufficientBalanceOrAllowance` in docs (#127) From 0ba0d2f8d1645f9ed79ca8dfc15e0bb49f5782ea Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 24 Aug 2017 10:02:45 +0200 Subject: [PATCH 6/8] Remove redundant else's --- src/contract_wrappers/token_registry_wrapper.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index 7a88d329de..693131200c 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -56,9 +56,8 @@ export class TokenRegistryWrapper extends ContractWrapper { const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.call(symbol); if (addressIfExists === constants.NULL_ADDRESS) { return undefined; - } else { - return addressIfExists; } + return addressIfExists; } public async getTokenAddressByNameIfExistsAsync(name: string): Promise { assert.isString('name', name); @@ -66,9 +65,8 @@ export class TokenRegistryWrapper extends ContractWrapper { const addressIfExists = await tokenRegistryContract.getTokenAddressByName.call(name); if (addressIfExists === constants.NULL_ADDRESS) { return undefined; - } else { - return addressIfExists; } + return addressIfExists; } public async getTokenBySymbolIfExistsAsync(symbol: string): Promise { assert.isString('symbol', symbol); From 5dce4c3b3b655c190100b480ef50a423f3344ee6 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 24 Aug 2017 10:04:56 +0200 Subject: [PATCH 7/8] Rename _getTokenByMetadata to _createTokenFromMetadata --- src/contract_wrappers/token_registry_wrapper.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts index 693131200c..5fee1304e2 100644 --- a/src/contract_wrappers/token_registry_wrapper.ts +++ b/src/contract_wrappers/token_registry_wrapper.ts @@ -47,7 +47,7 @@ export class TokenRegistryWrapper extends ContractWrapper { const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenMetaData.call(address); - const token = this._getTokenByMetadata(metadata); + const token = this._createTokenFromMetadata(metadata); return token; } public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise { @@ -72,17 +72,17 @@ export class TokenRegistryWrapper extends ContractWrapper { assert.isString('symbol', symbol); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenBySymbol.call(symbol); - const token = this._getTokenByMetadata(metadata); + const token = this._createTokenFromMetadata(metadata); return token; } public async getTokenByNameIfExistsAsync(name: string): Promise { assert.isString('name', name); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenByName.call(name); - const token = this._getTokenByMetadata(metadata); + const token = this._createTokenFromMetadata(metadata); return token; } - private _getTokenByMetadata(metadata: TokenMetadata): Token|undefined { + private _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined { if (metadata[0] === constants.NULL_ADDRESS) { return undefined; } From 933242bd9d83ccbf92ce29aa2b4606336e64eed7 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 24 Aug 2017 10:05:53 +0200 Subject: [PATCH 8/8] Change the unregistered token in tests --- 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 18f2f25413..e1702cd45b 100644 --- a/test/token_registry_wrapper_test.ts +++ b/test/token_registry_wrapper_test.ts @@ -24,8 +24,8 @@ describe('TokenRegistryWrapper', () => { const tokenByName: {[symbol: string]: Token} = {}; const registeredSymbol = 'ZRX'; const registeredName = '0x Protocol Token'; - const unregisteredSymbol = 'FUCK'; - const unregisteredName = 'FUCKtoken'; + const unregisteredSymbol = 'MAL'; + const unregisteredName = 'Malicious Token'; before(async () => { const web3 = web3Factory.create(); zeroEx = new ZeroEx(web3.currentProvider);