156 lines
5.6 KiB
TypeScript
156 lines
5.6 KiB
TypeScript
import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from '@0x/contracts-erc1155';
|
|
import { DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
|
|
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
|
import { constants, filterLogsToArguments, getRandomInteger, TransactionFactory } from '@0x/contracts-test-utils';
|
|
import { SignatureType, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types';
|
|
import { BigNumber } from '@0x/utils';
|
|
import * as _ from 'lodash';
|
|
|
|
import { AssertionResult } from '../assertions/function_assertion';
|
|
import { DeploymentManager } from '../deployment_manager';
|
|
import { SimulationEnvironment } from '../simulation';
|
|
|
|
export type Constructor<T = {}> = new (...args: any[]) => T;
|
|
|
|
export interface ActorConfig {
|
|
name?: string;
|
|
deployment: DeploymentManager;
|
|
[mixinProperty: string]: any;
|
|
}
|
|
|
|
export class Actor {
|
|
public static count: number = 0;
|
|
public readonly address: string;
|
|
public readonly name: string;
|
|
public readonly privateKey: Buffer;
|
|
public readonly deployment: DeploymentManager;
|
|
public simulationEnvironment?: SimulationEnvironment;
|
|
public simulationActions: {
|
|
[action: string]: AsyncIterableIterator<AssertionResult | void>;
|
|
} = {};
|
|
public mixins: string[] = [];
|
|
protected readonly _transactionFactory: TransactionFactory;
|
|
|
|
public static reset(): void {
|
|
Actor.count = 0;
|
|
}
|
|
|
|
constructor(config: ActorConfig) {
|
|
Actor.count++;
|
|
|
|
// Emit an error if the actor count is too high.
|
|
if (Actor.count >= config.deployment.accounts.length) {
|
|
throw new Error('Actor count too large');
|
|
}
|
|
|
|
this.address = config.deployment.accounts[Actor.count];
|
|
this.name = config.name || this.address;
|
|
this.deployment = config.deployment;
|
|
this.privateKey = constants.TESTRPC_PRIVATE_KEYS[config.deployment.accounts.indexOf(this.address)];
|
|
this._transactionFactory = new TransactionFactory(
|
|
this.privateKey,
|
|
config.deployment.exchange.address,
|
|
config.deployment.chainId,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Sets a balance for an ERC20 token and approves a spender (defaults to the ERC20 asset proxy)
|
|
* to transfer the token.
|
|
*/
|
|
public async configureERC20TokenAsync(
|
|
token: DummyERC20TokenContract | WETH9Contract,
|
|
spender?: string,
|
|
amount?: BigNumber,
|
|
): Promise<void> {
|
|
if (token instanceof DummyERC20TokenContract) {
|
|
await token
|
|
.setBalance(this.address, amount || constants.INITIAL_ERC20_BALANCE)
|
|
.awaitTransactionSuccessAsync();
|
|
} else {
|
|
await token.deposit().awaitTransactionSuccessAsync({
|
|
from: this.address,
|
|
value: amount || constants.ONE_ETHER,
|
|
});
|
|
}
|
|
|
|
await token
|
|
.approve(spender || this.deployment.assetProxies.erc20Proxy.address, constants.MAX_UINT256)
|
|
.awaitTransactionSuccessAsync({ from: this.address });
|
|
}
|
|
|
|
/**
|
|
* Mints some number of ERC721 NFTs and approves a spender (defaults to the ERC721 asset proxy)
|
|
* to transfer the token.
|
|
*/
|
|
public async configureERC721TokenAsync(
|
|
token: DummyERC721TokenContract,
|
|
spender?: string,
|
|
numToMint: number = 1,
|
|
): Promise<BigNumber[]> {
|
|
const tokenIds: BigNumber[] = [];
|
|
_.times(numToMint, async () => {
|
|
const tokenId = getRandomInteger(constants.ZERO_AMOUNT, constants.MAX_UINT256);
|
|
await token.mint(this.address, tokenId).awaitTransactionSuccessAsync({
|
|
from: this.address,
|
|
});
|
|
tokenIds.push(tokenId);
|
|
});
|
|
|
|
await token
|
|
.setApprovalForAll(spender || this.deployment.assetProxies.erc721Proxy.address, true)
|
|
.awaitTransactionSuccessAsync({
|
|
from: this.address,
|
|
});
|
|
return tokenIds;
|
|
}
|
|
|
|
/**
|
|
* Mints some number of ERC1115 fungible tokens and approves a spender (defaults to the ERC1155 asset proxy)
|
|
* to transfer the token.
|
|
*/
|
|
public async configureERC1155TokenAsync(
|
|
token: ERC1155MintableContract,
|
|
spender?: string,
|
|
amount?: BigNumber,
|
|
): Promise<BigNumber> {
|
|
// Create a fungible token.
|
|
const receipt = await token.create('', false).awaitTransactionSuccessAsync({ from: this.address });
|
|
const logs = filterLogsToArguments<ERC1155TransferSingleEventArgs>(receipt.logs, 'TransferSingle');
|
|
|
|
// Throw if the wrong number of logs were received.
|
|
if (logs.length !== 1) {
|
|
throw new Error('Invalid number of `TransferSingle` logs');
|
|
}
|
|
const { id } = logs[0];
|
|
|
|
// Mint the token
|
|
await token
|
|
.mintFungible(id, [this.address], [amount || new BigNumber(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)])
|
|
.awaitTransactionSuccessAsync({ from: this.address });
|
|
|
|
// Set approval for all token types for the spender.
|
|
await token
|
|
.setApprovalForAll(spender || this.deployment.assetProxies.erc1155Proxy.address, true)
|
|
.awaitTransactionSuccessAsync({ from: this.address });
|
|
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* Signs a transaction.
|
|
*/
|
|
public async signTransactionAsync(
|
|
customTransactionParams: Partial<ZeroExTransaction>,
|
|
signatureType: SignatureType = SignatureType.EthSign,
|
|
): Promise<SignedZeroExTransaction> {
|
|
return this._transactionFactory.newSignedTransactionAsync(
|
|
{
|
|
gasPrice: DeploymentManager.gasPrice,
|
|
...customTransactionParams,
|
|
},
|
|
signatureType,
|
|
);
|
|
}
|
|
}
|