diff options
Diffstat (limited to 'contracts/protocol/test/utils/erc721_wrapper.ts')
-rw-r--r-- | contracts/protocol/test/utils/erc721_wrapper.ts | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/contracts/protocol/test/utils/erc721_wrapper.ts b/contracts/protocol/test/utils/erc721_wrapper.ts new file mode 100644 index 000000000..1f658ce86 --- /dev/null +++ b/contracts/protocol/test/utils/erc721_wrapper.ts @@ -0,0 +1,236 @@ +import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils'; +import { artifacts as tokensArtifacts, DummyERC721TokenContract } from '@0x/contracts-tokens'; +import { generatePseudoRandomSalt } from '@0x/order-utils'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { Provider } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy'; +import { artifacts } from '../../src/artifacts'; + +export class ERC721Wrapper { + private readonly _tokenOwnerAddresses: string[]; + private readonly _contractOwnerAddress: string; + private readonly _web3Wrapper: Web3Wrapper; + private readonly _provider: Provider; + private readonly _dummyTokenContracts: DummyERC721TokenContract[]; + private _proxyContract?: ERC721ProxyContract; + private _proxyIdIfExists?: string; + private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; + constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { + this._web3Wrapper = new Web3Wrapper(provider); + this._provider = provider; + this._dummyTokenContracts = []; + this._tokenOwnerAddresses = tokenOwnerAddresses; + this._contractOwnerAddress = contractOwnerAddress; + } + public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> { + // tslint:disable-next-line:no-unused-variable + for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) { + this._dummyTokenContracts.push( + await DummyERC721TokenContract.deployFrom0xArtifactAsync( + tokensArtifacts.DummyERC721Token, + this._provider, + txDefaults, + constants.DUMMY_TOKEN_NAME, + constants.DUMMY_TOKEN_SYMBOL, + ), + ); + } + return this._dummyTokenContracts; + } + public async deployProxyAsync(): Promise<ERC721ProxyContract> { + this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync( + artifacts.ERC721Proxy, + this._provider, + txDefaults, + ); + this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); + return this._proxyContract; + } + public getProxyId(): string { + this._validateProxyContractExistsOrThrow(); + return this._proxyIdIfExists as string; + } + public async setBalancesAndAllowancesAsync(): Promise<void> { + this._validateDummyTokenContractsExistOrThrow(); + this._validateProxyContractExistsOrThrow(); + this._initialTokenIdsByOwner = {}; + for (const dummyTokenContract of this._dummyTokenContracts) { + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + // tslint:disable-next-line:no-unused-variable + for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) { + const tokenId = generatePseudoRandomSalt(); + await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); + if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) { + this._initialTokenIdsByOwner[tokenOwnerAddress] = { + [dummyTokenContract.address]: [], + }; + } + if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address])) { + this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = []; + } + this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); + + await this.approveProxyAsync(dummyTokenContract.address, tokenId); + } + } + } + } + public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const owner = await tokenContract.ownerOf.callAsync(tokenId); + const doesExist = owner !== constants.NULL_ADDRESS; + return doesExist; + } + public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> { + const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; + await this.approveAsync(proxyAddress, tokenAddress, tokenId); + } + public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); + const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.setApprovalForAll.sendTransactionAsync(proxyAddress, isApproved, { + from: tokenOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.approve.sendTransactionAsync(to, tokenId, { + from: tokenOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async transferFromAsync( + tokenAddress: string, + tokenId: BigNumber, + currentOwner: string, + userAddress: string, + ): Promise<void> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.transferFrom.sendTransactionAsync(currentOwner, userAddress, tokenId, { + from: currentOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.mint.sendTransactionAsync(userAddress, tokenId, { + from: this._contractOwnerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.burn.sendTransactionAsync(owner, tokenId, { + from: this._contractOwnerAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const owner = await tokenContract.ownerOf.callAsync(tokenId); + return owner; + } + public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); + const isOwner = tokenOwner === userAddress; + return isOwner; + } + public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> { + this._validateProxyContractExistsOrThrow(); + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const operator = (this._proxyContract as ERC721ProxyContract).address; + const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); + return didApproveAll; + } + public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { + this._validateProxyContractExistsOrThrow(); + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const approvedAddress = await tokenContract.getApproved.callAsync(tokenId); + const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; + const isProxyAnApprovedOperator = approvedAddress === proxyAddress; + return isProxyAnApprovedOperator; + } + public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> { + this._validateDummyTokenContractsExistOrThrow(); + this._validateBalancesAndAllowancesSetOrThrow(); + const tokenIdsByOwner: ERC721TokenIdsByOwner = {}; + const tokenOwnerAddresses: string[] = []; + const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = []; + for (const dummyTokenContract of this._dummyTokenContracts) { + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][ + dummyTokenContract.address + ]; + for (const tokenId of initialTokenOwnerIds) { + tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId)); + tokenInfo.push({ + tokenId, + tokenAddress: dummyTokenContract.address, + }); + } + } + } + _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => { + const tokenAddress = tokenInfo[ownerIndex].tokenAddress; + const tokenId = tokenInfo[ownerIndex].tokenId; + if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress])) { + tokenIdsByOwner[tokenOwnerAddress] = { + [tokenAddress]: [], + }; + } + if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress][tokenAddress])) { + tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = []; + } + tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId); + }); + return tokenIdsByOwner; + } + public getTokenOwnerAddresses(): string[] { + return this._tokenOwnerAddresses; + } + public getTokenAddresses(): string[] { + const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); + return tokenAddresses; + } + private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract { + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); + } + return tokenContractIfExists; + } + private _validateDummyTokenContractsExistOrThrow(): void { + if (_.isUndefined(this._dummyTokenContracts)) { + throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"'); + } + } + private _validateProxyContractExistsOrThrow(): void { + if (_.isUndefined(this._proxyContract)) { + throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"'); + } + } + private _validateBalancesAndAllowancesSetOrThrow(): void { + if (_.keys(this._initialTokenIdsByOwner).length === 0) { + throw new Error( + 'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', + ); + } + } +} |