Added BalanceChecker contract (#60)
* Added BalanceChecker contract * Upgraded to solidity 0.6, simplified contract, added tests * uint -> uint256 * export BalanceChecker contract wrapper * prettier * removed superfluous test code * prettier
This commit is contained in:
parent
23ee108089
commit
0a37a588e8
89
packages/asset-swapper/contracts/src/BalanceChecker.sol
Normal file
89
packages/asset-swapper/contracts/src/BalanceChecker.sol
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2020 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.6;
|
||||||
|
|
||||||
|
// ERC20 contract interface
|
||||||
|
abstract contract IToken {
|
||||||
|
/// @dev Query the balance of owner
|
||||||
|
/// @param _owner The address from which the balance will be retrieved
|
||||||
|
/// @return Balance of owner
|
||||||
|
function balanceOf(address _owner) public virtual view returns (uint256);
|
||||||
|
|
||||||
|
/// @param _owner The address of the account owning tokens
|
||||||
|
/// @param _spender The address of the account able to transfer the tokens
|
||||||
|
/// @return Amount of remaining tokens allowed to spent
|
||||||
|
function allowance(address _owner, address _spender) public virtual view returns (uint256);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract BalanceChecker {
|
||||||
|
/*
|
||||||
|
Check the token balances of wallet-token pairs.
|
||||||
|
Pass 0xeee... as a "token" address to get ETH balance.
|
||||||
|
Possible error throws:
|
||||||
|
- extremely large arrays for user and or tokens (gas cost too high)
|
||||||
|
|
||||||
|
Returns a one-dimensional that's user.length long.
|
||||||
|
*/
|
||||||
|
function balances(address[] calldata users, address[] calldata tokens) external view returns (uint256[] memory) {
|
||||||
|
// make sure the users array and tokens array are of equal length
|
||||||
|
require(users.length == tokens.length, "users array is a different length than the tokens array");
|
||||||
|
|
||||||
|
uint256[] memory addrBalances = new uint256[](users.length);
|
||||||
|
|
||||||
|
for(uint i = 0; i < users.length; i++) {
|
||||||
|
if (tokens[i] != address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)) {
|
||||||
|
addrBalances[i] = IToken(tokens[i]).balanceOf(users[i]);
|
||||||
|
} else {
|
||||||
|
addrBalances[i] = users[i].balance; // ETH balance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrBalances;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check the allowances of an array of owner-spender-tokens
|
||||||
|
|
||||||
|
Returns 0 for 0xeee... (ETH)
|
||||||
|
Possible error throws:
|
||||||
|
- extremely large arrays for user and or tokens (gas cost too high)
|
||||||
|
|
||||||
|
Returns a one-dimensional array that's owners.length long.
|
||||||
|
*/
|
||||||
|
function allowances(address[] calldata owners, address[] calldata spenders, address[] calldata tokens) external view returns (uint256[] memory) {
|
||||||
|
// make sure the arrays are all of equal length
|
||||||
|
require(owners.length == spenders.length, "all arrays must be of equal length");
|
||||||
|
require(owners.length == tokens.length, "all arrays must be of equal length");
|
||||||
|
|
||||||
|
uint256[] memory addrAllowances = new uint256[](owners.length);
|
||||||
|
|
||||||
|
for(uint i = 0; i < owners.length; i++) {
|
||||||
|
if (tokens[i] != address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)) {
|
||||||
|
addrAllowances[i] = IToken(tokens[i]).allowance(owners[i], spenders[i]);
|
||||||
|
} else {
|
||||||
|
// ETH
|
||||||
|
addrAllowances[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrAllowances;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -36,9 +36,9 @@
|
|||||||
"publish:private": "yarn build && gitpkg publish"
|
"publish:private": "yarn build && gitpkg publish"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler",
|
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
||||||
"postpublish": {
|
"postpublish": {
|
||||||
"assets": []
|
"assets": []
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
import { ContractArtifact } from 'ethereum-types';
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as BalanceChecker from '../generated-artifacts/BalanceChecker.json';
|
||||||
import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json';
|
import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json';
|
||||||
export const artifacts = { ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact };
|
export const artifacts = {
|
||||||
|
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||||
|
BalanceChecker: BalanceChecker as ContractArtifact,
|
||||||
|
};
|
||||||
|
@ -177,7 +177,7 @@ export {
|
|||||||
} from './utils/quote_report_generator';
|
} from './utils/quote_report_generator';
|
||||||
export { QuoteRequestor } from './utils/quote_requestor';
|
export { QuoteRequestor } from './utils/quote_requestor';
|
||||||
export { rfqtMocker } from './utils/rfqt_mocker';
|
export { rfqtMocker } from './utils/rfqt_mocker';
|
||||||
export { ERC20BridgeSamplerContract } from './wrappers';
|
export { ERC20BridgeSamplerContract, BalanceCheckerContract } from './wrappers';
|
||||||
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
|
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
|
||||||
export type Native = ERC20BridgeSource.Native;
|
export type Native = ERC20BridgeSource.Native;
|
||||||
export type MultiHop = ERC20BridgeSource.MultiHop;
|
export type MultiHop = ERC20BridgeSource.MultiHop;
|
||||||
|
@ -3,4 +3,5 @@
|
|||||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
export * from '../generated-wrappers/balance_checker';
|
||||||
export * from '../generated-wrappers/erc20_bridge_sampler';
|
export * from '../generated-wrappers/erc20_bridge_sampler';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import { ContractArtifact } from 'ethereum-types';
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
|
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
|
||||||
|
import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json';
|
||||||
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
|
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
|
||||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
||||||
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
||||||
@ -39,6 +40,7 @@ import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json
|
|||||||
import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.json';
|
import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.json';
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
ApproximateBuys: ApproximateBuys as ContractArtifact,
|
ApproximateBuys: ApproximateBuys as ContractArtifact,
|
||||||
|
BalanceChecker: BalanceChecker as ContractArtifact,
|
||||||
BalancerSampler: BalancerSampler as ContractArtifact,
|
BalancerSampler: BalancerSampler as ContractArtifact,
|
||||||
CurveSampler: CurveSampler as ContractArtifact,
|
CurveSampler: CurveSampler as ContractArtifact,
|
||||||
DODOSampler: DODOSampler as ContractArtifact,
|
DODOSampler: DODOSampler as ContractArtifact,
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
|
import { blockchainTests, constants, expect, web3Wrapper } from '@0x/contracts-test-utils';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { artifacts } from '../artifacts';
|
||||||
|
import { BalanceCheckerContract } from '../wrappers';
|
||||||
|
|
||||||
|
// tslint:disable: custom-no-magic-numbers
|
||||||
|
|
||||||
|
const ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
||||||
|
|
||||||
|
blockchainTests.resets('BalanceChecker contract', env => {
|
||||||
|
let contract: BalanceCheckerContract;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
contract = await BalanceCheckerContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.BalanceChecker,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getBalances', () => {
|
||||||
|
it('returns the correct array for a successful call', async () => {
|
||||||
|
const makerToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||||
|
erc20Artifacts.DummyERC20Token,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
constants.DUMMY_TOKEN_NAME,
|
||||||
|
constants.DUMMY_TOKEN_SYMBOL,
|
||||||
|
new BigNumber(18),
|
||||||
|
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
|
||||||
|
);
|
||||||
|
|
||||||
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
const owner = accounts[0];
|
||||||
|
const owner2 = accounts[1];
|
||||||
|
|
||||||
|
await makerToken.mint(new BigNumber(100)).awaitTransactionSuccessAsync({ from: owner });
|
||||||
|
|
||||||
|
const testResults = await contract.balances([owner, owner2], [makerToken.address, ETH_ADDRESS]).callAsync();
|
||||||
|
|
||||||
|
expect(testResults).to.eql([new BigNumber(100), new BigNumber(100000000000000000000)]);
|
||||||
|
});
|
||||||
|
it('it throws an error if the input arrays of different lengths', async () => {
|
||||||
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
const owner = accounts[0];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await contract.balances([owner], [ETH_ADDRESS, ETH_ADDRESS]).callAsync();
|
||||||
|
expect.fail();
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.message).to.eql('users array is a different length than the tokens array');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -4,6 +4,7 @@
|
|||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
export * from '../test/generated-wrappers/approximate_buys';
|
export * from '../test/generated-wrappers/approximate_buys';
|
||||||
|
export * from '../test/generated-wrappers/balance_checker';
|
||||||
export * from '../test/generated-wrappers/balancer_sampler';
|
export * from '../test/generated-wrappers/balancer_sampler';
|
||||||
export * from '../test/generated-wrappers/curve_sampler';
|
export * from '../test/generated-wrappers/curve_sampler';
|
||||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
"files": [
|
"files": [
|
||||||
|
"generated-artifacts/BalanceChecker.json",
|
||||||
"generated-artifacts/ERC20BridgeSampler.json",
|
"generated-artifacts/ERC20BridgeSampler.json",
|
||||||
"test/generated-artifacts/ApproximateBuys.json",
|
"test/generated-artifacts/ApproximateBuys.json",
|
||||||
|
"test/generated-artifacts/BalanceChecker.json",
|
||||||
"test/generated-artifacts/BalancerSampler.json",
|
"test/generated-artifacts/BalancerSampler.json",
|
||||||
"test/generated-artifacts/CurveSampler.json",
|
"test/generated-artifacts/CurveSampler.json",
|
||||||
"test/generated-artifacts/DODOSampler.json",
|
"test/generated-artifacts/DODOSampler.json",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user