import * as _ from 'lodash'; import {artifacts} from '../artifacts'; import {Token, TokenMetadata, TokenRegistryContract, ZeroExError} from '../types'; import {assert} from '../utils/assert'; import {constants} from '../utils/constants'; import {Web3Wrapper} from '../web3_wrapper'; import {ContractWrapper} from './contract_wrapper'; /** * 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].toNumber(), }; return token; } constructor(web3Wrapper: Web3Wrapper, contractAddressIfExists?: string) { super(web3Wrapper); 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 tokenRegistryContract = await this._getTokenRegistryContractAsync(); 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(); 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. */ public async getTokenIfExistsAsync(address: string): Promise { assert.isETHAddressHex('address', address); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address); 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.TokenRegistryArtifact, this._contractAddressIfExists, ); return contractAddress; } private _invalidateContractInstance(): void { delete this._tokenRegistryContractIfExists; } private async _getTokenRegistryContractAsync(): Promise { if (!_.isUndefined(this._tokenRegistryContractIfExists)) { return this._tokenRegistryContractIfExists; } const contractInstance = await this._instantiateContractIfExistsAsync( artifacts.TokenRegistryArtifact, this._contractAddressIfExists, ); this._tokenRegistryContractIfExists = contractInstance; return this._tokenRegistryContractIfExists; } }