From 48b44342ab1642a78d0485e111019acfdbbfdfd5 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Sun, 22 Apr 2018 15:17:55 -0700 Subject: Add ERC721 wrapper --- packages/contracts/src/utils/erc721_wrapper.ts | 154 +++++++++++++++++++++++++ packages/contracts/src/utils/types.ts | 27 ++--- 2 files changed, 161 insertions(+), 20 deletions(-) create mode 100644 packages/contracts/src/utils/erc721_wrapper.ts (limited to 'packages/contracts') diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts new file mode 100644 index 000000000..5b79e5ddb --- /dev/null +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -0,0 +1,154 @@ +import { ZeroEx } from '0x.js'; +import { Deployer } from '@0xproject/deployer'; +import { Provider } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token'; +import { ERC721ProxyContract } from '../contract_wrappers/generated/e_r_c721_proxy'; + +import { constants } from './constants'; +import { ContractName, ERC721BalancesByOwner } from './types'; + +export class ERC721Wrapper { + private _tokenOwnerAddresses: string[]; + private _contractOwnerAddress: string; + private _deployer: Deployer; + private _provider: Provider; + private _dummyERC721TokenContracts?: DummyERC721TokenContract[]; + private _erc721ProxyContract?: ERC721ProxyContract; + private _initialERC721BalancesByOwner?: ERC721BalancesByOwner; + constructor(deployer: Deployer, provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { + this._deployer = deployer; + this._provider = provider; + this._tokenOwnerAddresses = tokenOwnerAddresses; + this._contractOwnerAddress = contractOwnerAddress; + } + public async deployDummyERC721TokensAsync(): Promise { + const tokenContractInstances = await Promise.all( + _.map(this._tokenOwnerAddresses, tokenOwnerAddress => + this._deployer.deployAsync(ContractName.DummyERC721Token, constants.DUMMY_ERC721_TOKEN_ARGS), + ), + ); + this._dummyERC721TokenContracts = _.map( + tokenContractInstances, + tokenContractInstance => + new DummyERC721TokenContract(tokenContractInstance.abi, tokenContractInstance.address, this._provider), + ); + return this._dummyERC721TokenContracts; + } + public async deployERC721ProxyAsync(): Promise { + const proxyContractInstance = await this._deployer.deployAsync(ContractName.ERC721Proxy); + this._erc721ProxyContract = new ERC721ProxyContract( + proxyContractInstance.abi, + proxyContractInstance.address, + this._provider, + ); + return this._erc721ProxyContract; + } + public async setBalancesAndAllowancesAsync() { + if (_.isUndefined(this._dummyERC721TokenContracts)) { + throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyERC721TokensAsync"'); + } + if (_.isUndefined(this._erc721ProxyContract)) { + throw new Error('ERC721 proxy contract not yet deployed, please call "deployERC721ProxyAsync"'); + } + const setBalancePromises: any[] = []; + const setAllowancePromises: any[] = []; + this._initialERC721BalancesByOwner = {}; + _.forEach(this._dummyERC721TokenContracts, dummyERC721TokenContract => { + _.forEach(this._tokenOwnerAddresses, tokenOwnerAddress => { + _.forEach(_.range(constants.NUM_ERC721_TOKENS_TO_MINT), () => { + const tokenId = ZeroEx.generatePseudoRandomSalt(); + setBalancePromises.push( + dummyERC721TokenContract.mint.sendTransactionAsync(tokenOwnerAddress, tokenId, { + from: this._contractOwnerAddress, + }), + ); + if ( + _.isUndefined((this._initialERC721BalancesByOwner as ERC721BalancesByOwner)[tokenOwnerAddress]) + ) { + (this._initialERC721BalancesByOwner as ERC721BalancesByOwner)[tokenOwnerAddress] = { + [dummyERC721TokenContract.address]: [], + }; + } + if ( + _.isUndefined( + (this._initialERC721BalancesByOwner as ERC721BalancesByOwner)[tokenOwnerAddress][ + dummyERC721TokenContract.address + ], + ) + ) { + (this._initialERC721BalancesByOwner as ERC721BalancesByOwner)[tokenOwnerAddress][ + dummyERC721TokenContract.address + ] = []; + } + (this._initialERC721BalancesByOwner as ERC721BalancesByOwner)[tokenOwnerAddress][ + dummyERC721TokenContract.address + ].push(tokenId); + }); + const approval = true; + setAllowancePromises.push( + dummyERC721TokenContract.setApprovalForAll.sendTransactionAsync( + (this._erc721ProxyContract as ERC721ProxyContract).address, + approval, + { from: tokenOwnerAddress }, + ), + ); + }); + }); + await Promise.all([...setBalancePromises, ...setAllowancePromises]); + } + public async getBalancesAsync(): Promise { + if (_.isUndefined(this._dummyERC721TokenContracts)) { + throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyERC721TokensAsync"'); + } + if (_.isUndefined(this._initialERC721BalancesByOwner)) { + throw new Error( + 'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', + ); + } + const balancesByOwner: ERC721BalancesByOwner = {}; + const tokenOwnerPromises: any[] = []; + const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = []; + _.forEach(this._dummyERC721TokenContracts, dummyERC721TokenContract => { + _.forEach(this._tokenOwnerAddresses, tokenOwnerAddress => { + const initialTokenOwnerIds = (this._initialERC721BalancesByOwner as ERC721BalancesByOwner)[ + tokenOwnerAddress + ][dummyERC721TokenContract.address]; + _.forEach(initialTokenOwnerIds, tokenId => { + tokenOwnerPromises.push(dummyERC721TokenContract.ownerOf.callAsync(tokenId)); + tokenInfo.push({ + tokenId, + tokenAddress: dummyERC721TokenContract.address, + }); + }); + }); + }); + const tokenOwnerAddresses = await Promise.all(tokenOwnerPromises); + _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => { + const tokenAddress = tokenInfo[ownerIndex].tokenAddress; + const tokenId = tokenInfo[ownerIndex].tokenId; + if (_.isUndefined(balancesByOwner[tokenOwnerAddress])) { + balancesByOwner[tokenOwnerAddress] = { + [tokenAddress]: [], + }; + } + if (_.isUndefined(balancesByOwner[tokenOwnerAddress][tokenAddress])) { + balancesByOwner[tokenOwnerAddress][tokenAddress] = []; + } + balancesByOwner[tokenOwnerAddress][tokenAddress].push(tokenId); + }); + return balancesByOwner; + } + public getTokenOwnerAddresses(): string[] { + return this._tokenOwnerAddresses; + } + public getTokenAddresses(): string[] { + const tokenAddresses = _.map( + this._dummyERC721TokenContracts, + dummyERC721TokenContract => dummyERC721TokenContract.address, + ); + return tokenAddresses; + } +} diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 8bc9641fc..629187e95 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -1,12 +1,18 @@ import { AbiDefinition, ContractAbi } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; -export interface BalancesByOwner { +export interface ERC20BalancesByOwner { [ownerAddress: string]: { [tokenAddress: string]: BigNumber; }; } +export interface ERC721BalancesByOwner { + [ownerAddress: string]: { + [tokenAddress: string]: BigNumber[]; + }; +} + export interface SubmissionContractEventArgs { transactionId: BigNumber; } @@ -43,20 +49,6 @@ export enum AssetProxyId { ERC721, } -export interface DefaultOrderParams { - exchangeAddress: string; - makerAddress: string; - feeRecipientAddress: string; - makerAssetAddress: string; - takerAssetAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - makerAssetData: string; - takerAssetData: string; -} - export interface TransactionDataParams { name: string; abi: AbiDefinition[]; @@ -82,11 +74,6 @@ export interface Token { swarmHash: string; } -export interface TokenInfoByNetwork { - development: Token[]; - live: Token[]; -} - export enum ExchangeContractErrs { ERROR_ORDER_EXPIRED, ERROR_ORDER_FULLY_FILLED, -- cgit v1.2.3