* Stop restarting node unnecesssarily during test * Add new, empty LibAssetData * Support encoding & decoding of ERC20 asset data * Support encoding & decoding of ERC721 asset data * Support encoding & decoding of ERC1155 asset data * Support encoding & decoding of multi-asset data * Support querying ERC20 balance from asset data * Support querying ERC721 balance from asset data * Support querying ERC1155 balance from asset data * Support querying balance from multi-asset data * Support querying ERC20 allowance from asset data * Support querying ERC721 allowance from asset data * Support querying ERC1155 allowance from asset data * In tests, wait for allowance set before checking * Introduce temporary variable `assetDataBody` * Handle edge case in multi-asset balance query * Support multi-asset allowance query by asset data * Move variable declaration up for readability. * Make all solhint-disable's cite specific rules And move the directives to the ends of lines whenever possible * Rename query tests to include " by asset data" * Extract test helper method * Extract another test helper method * Support batch queries of allowances & balances * In LibAssetData.sol, use IERC1155, not ...Mintable * Rename balance*() return vars: amount -> balance * Fix bug in ERC721 balance query Was using method balanceOf(), but needed to be using ownerOf(). getERC721TokenOwner() method lifted from @0x/extensions/contracts/src/OrderValidator/OrderValidator.sol * Reuse new en/decoders; avoid abi.decode(). * Start lowest allowance/balance from 0, not MAX_INT * Properly implement ERC1155 balance querying * Split lines for readability * Also check isApprovedForAll in 721 allowance query * Add neglected division of allowances by amounts * Rename methods: balanceOf -> getBalance * Rename methods: allowance -> getAllowance * Add methods: getBalanceAndAllowance() & batch...() * Rename return vars: amount -> allowance * Add devdoc comments * Rename batchGet* methods to getBatch* * Remove refactoring relic * Add revert messages to all require() calls * Reduce gas usage for ERC1155 asset data decoding * Don't use dockerized solc for ERC20 contracts Because they demand solc version 0.4.26, and it seems as though the tag for that version has been deleted from dockerhub. Without this, @0x/contracts-erc20 was failing to build. * Rename batch functions to use plurals * Skip dockerized solc for contracts needing 0.4.26 I seems as though the tag for that version has been deleted from dockerhub. Without this, these contracts were failing to build. * Make revert reasons follow snake case convention
154 lines
6.5 KiB
TypeScript
154 lines
6.5 KiB
TypeScript
import {
|
|
addressUtils,
|
|
chaiSetup,
|
|
expectContractCallFailedAsync,
|
|
provider,
|
|
txDefaults,
|
|
web3Wrapper,
|
|
} from '@0x/contracts-test-utils';
|
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
|
import { RevertReason } from '@0x/types';
|
|
import { BigNumber } from '@0x/utils';
|
|
import * as chai from 'chai';
|
|
import * as _ from 'lodash';
|
|
|
|
import { artifacts, TestLibAddressArrayContract } from '../src';
|
|
|
|
chaiSetup.configure();
|
|
const expect = chai.expect;
|
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
|
|
|
describe('LibAddressArray', () => {
|
|
let lib: TestLibAddressArrayContract;
|
|
|
|
before(async () => {
|
|
await blockchainLifecycle.startAsync();
|
|
// Deploy LibAddressArray
|
|
lib = await TestLibAddressArrayContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestLibAddressArray,
|
|
provider,
|
|
txDefaults,
|
|
);
|
|
});
|
|
after(async () => {
|
|
await blockchainLifecycle.revertAsync();
|
|
});
|
|
|
|
describe('append', () => {
|
|
it('should append to empty array', async () => {
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const result = await lib.publicAppend.callAsync([], addr);
|
|
const expected = [addr];
|
|
expect(result).to.deep.equal(expected);
|
|
});
|
|
|
|
it('should append to non-empty array', async () => {
|
|
const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const expected = [...arr, addr];
|
|
const result = await lib.publicAppend.callAsync(arr, addr);
|
|
expect(result).to.deep.equal(expected);
|
|
});
|
|
|
|
it('should revert if the free memory pointer was moved to before the end of the array', async () => {
|
|
const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const freeMemOffset = new BigNumber(-1);
|
|
return expectContractCallFailedAsync(
|
|
lib.testAppendRealloc.callAsync(arr, freeMemOffset, addr),
|
|
RevertReason.InvalidFreeMemoryPtr,
|
|
);
|
|
});
|
|
|
|
it('should keep the same memory address if free memory pointer does not move', async () => {
|
|
const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const freeMemOffset = new BigNumber(0);
|
|
const expected = [...arr, addr];
|
|
const [result, oldArrayMemStart, newArrayMemStart] = await lib.testAppendRealloc.callAsync(
|
|
arr,
|
|
freeMemOffset,
|
|
addr,
|
|
);
|
|
expect(result).to.deep.equal(expected);
|
|
expect(newArrayMemStart).bignumber.to.be.equal(oldArrayMemStart);
|
|
});
|
|
|
|
it('should change memory address if free memory pointer advances', async () => {
|
|
const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const freeMemOffset = new BigNumber(1);
|
|
const expectedArray = [...arr, addr];
|
|
const [result, oldArrayMemStart, newArrayMemStart] = await lib.testAppendRealloc.callAsync(
|
|
arr,
|
|
freeMemOffset,
|
|
addr,
|
|
);
|
|
// The new location should be the end of the old array + freeMemOffset.
|
|
const expectedNewArrayMemStart = oldArrayMemStart.plus((arr.length + 1) * 32).plus(freeMemOffset);
|
|
expect(result).to.deep.equal(expectedArray);
|
|
expect(newArrayMemStart).bignumber.to.be.equal(expectedNewArrayMemStart);
|
|
});
|
|
});
|
|
|
|
describe('contains', () => {
|
|
it('should return false on an empty array', async () => {
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const isFound = await lib.publicContains.callAsync([], addr);
|
|
expect(isFound).to.equal(false);
|
|
});
|
|
|
|
it('should return false on a missing item', async () => {
|
|
const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const isFound = await lib.publicContains.callAsync(arr, addr);
|
|
expect(isFound).to.equal(false);
|
|
});
|
|
|
|
it('should return true on an included item', async () => {
|
|
const arr = _.times(4, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = _.sample(arr) as string;
|
|
const isFound = await lib.publicContains.callAsync(arr, addr);
|
|
expect(isFound).to.equal(true);
|
|
});
|
|
|
|
it('should return true on the only item in the array', async () => {
|
|
const arr = _.times(1, () => addressUtils.generatePseudoRandomAddress());
|
|
const isFound = await lib.publicContains.callAsync(arr, arr[0]);
|
|
expect(isFound).to.equal(true);
|
|
});
|
|
});
|
|
|
|
describe('indexOf', () => {
|
|
it('should fail on an empty array', async () => {
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const [isSuccess] = await lib.publicIndexOf.callAsync([], addr);
|
|
expect(isSuccess).to.equal(false);
|
|
});
|
|
|
|
it('should fail on a missing item', async () => {
|
|
const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress());
|
|
const addr = addressUtils.generatePseudoRandomAddress();
|
|
const [isSuccess] = await lib.publicIndexOf.callAsync(arr, addr);
|
|
expect(isSuccess).to.equal(false);
|
|
});
|
|
|
|
it('should succeed on an included item', async () => {
|
|
const arr = _.times(4, () => addressUtils.generatePseudoRandomAddress());
|
|
const expectedIndexOf = _.random(0, arr.length - 1);
|
|
const addr = arr[expectedIndexOf];
|
|
const [isSuccess, index] = await lib.publicIndexOf.callAsync(arr, addr);
|
|
expect(isSuccess).to.equal(true);
|
|
expect(index).bignumber.to.equal(expectedIndexOf);
|
|
});
|
|
|
|
it('should succeed on the only item in the array', async () => {
|
|
const arr = _.times(1, () => addressUtils.generatePseudoRandomAddress());
|
|
const [isSuccess, index] = await lib.publicIndexOf.callAsync(arr, arr[0]);
|
|
expect(isSuccess).to.equal(true);
|
|
expect(index).bignumber.to.equal(0);
|
|
});
|
|
});
|
|
});
|
|
// tslint:disable:max-file-line-count
|