@0x/contracts-erc20-bridge-aggregator
: Create package.
`@0x/contracts-erc20`: Add `decimals()` to `LibERC20Token`. `@0x/contracts-erc20-bridge-sampler`: Created package.
This commit is contained in:
parent
c3c8ee7292
commit
0af346aad8
10
contracts/erc20-bridge-sampler/.npmignore
Normal file
10
contracts/erc20-bridge-sampler/.npmignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Blacklist all files
|
||||||
|
.*
|
||||||
|
*
|
||||||
|
# Whitelist lib
|
||||||
|
!lib/**/*
|
||||||
|
# Whitelist Solidity contracts
|
||||||
|
!contracts/src/**/*
|
||||||
|
# Blacklist tests in lib
|
||||||
|
/lib/test/*
|
||||||
|
# Package specific ignore
|
11
contracts/erc20-bridge-sampler/CHANGELOG.json
Normal file
11
contracts/erc20-bridge-sampler/CHANGELOG.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"version": "1.0.0-beta.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Created package.",
|
||||||
|
"pr": "TODO"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
0
contracts/erc20-bridge-sampler/CHANGELOG.md
Normal file
0
contracts/erc20-bridge-sampler/CHANGELOG.md
Normal file
17
contracts/erc20-bridge-sampler/DEPLOYS.json
Normal file
17
contracts/erc20-bridge-sampler/DEPLOYS.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Exchange",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "protocol v2 deploy",
|
||||||
|
"networks": {
|
||||||
|
"1": "0xBDB58Fdf0a1587a0a258330a184Bb2C6cbA0aabe",
|
||||||
|
"3": "0x0000000000000000000000000000000000000000",
|
||||||
|
"4": "0x0000000000000000000000000000000000000000",
|
||||||
|
"42": "0x0000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
3
contracts/erc20-bridge-sampler/README.md
Normal file
3
contracts/erc20-bridge-sampler/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## ERC20BridgeSampler
|
||||||
|
|
||||||
|
These are contracts used in DEX aggregation.
|
26
contracts/erc20-bridge-sampler/compiler.json
Normal file
26
contracts/erc20-bridge-sampler/compiler.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./test/generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"useDockerisedSolc": false,
|
||||||
|
"isOfflineMode": false,
|
||||||
|
"compilerSettings": {
|
||||||
|
"evmVersion": "constantinople",
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000,
|
||||||
|
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"devdoc",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,320 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol";
|
||||||
|
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||||
|
import "./IERC20BridgeSampler.sol";
|
||||||
|
import "./IExchange.sol";
|
||||||
|
import "./IEth2Dai.sol";
|
||||||
|
import "./IKyberNetwork.sol";
|
||||||
|
import "./IUniswapExchange.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract ERC20BridgeSampler is
|
||||||
|
IERC20BridgeSampler
|
||||||
|
{
|
||||||
|
bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||||
|
address constant public EXCHANGE_ADDRESS = 0x080bf510FCbF18b91105470639e9561022937712; // V2
|
||||||
|
address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||||
|
address constant public UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||||
|
address constant public KYBER_NETWORK_PROXY_ADDRESS = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
|
||||||
|
address constant public WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||||
|
address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||||
|
|
||||||
|
function queryOrdersAndSampleSells(
|
||||||
|
IExchange.Order[] memory orders,
|
||||||
|
address[] memory sources,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
IExchange.OrderInfo[] memory orderInfos,
|
||||||
|
uint256[][] memory makerTokenAmountsBySource
|
||||||
|
)
|
||||||
|
{
|
||||||
|
require(orders.length != 0, "EMPTY_ORDERS");
|
||||||
|
orderInfos = queryOrders(orders);
|
||||||
|
makerTokenAmountsBySource = sampleSells(
|
||||||
|
sources,
|
||||||
|
_assetDataToTokenAddress(orders[0].takerAssetData),
|
||||||
|
_assetDataToTokenAddress(orders[0].makerAssetData),
|
||||||
|
takerTokenAmounts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryOrdersAndSampleBuys(
|
||||||
|
IExchange.Order[] memory orders,
|
||||||
|
address[] memory sources,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
IExchange.OrderInfo[] memory orderInfos,
|
||||||
|
uint256[][] memory makerTokenAmountsBySource
|
||||||
|
)
|
||||||
|
{
|
||||||
|
orderInfos = queryOrders(orders);
|
||||||
|
makerTokenAmountsBySource = sampleBuys(
|
||||||
|
sources,
|
||||||
|
_assetDataToTokenAddress(orders[0].takerAssetData),
|
||||||
|
_assetDataToTokenAddress(orders[0].makerAssetData),
|
||||||
|
makerTokenAmounts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryOrders(IExchange.Order[] memory orders)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (IExchange.OrderInfo[] memory orderInfos)
|
||||||
|
{
|
||||||
|
uint256 numOrders = orders.length;
|
||||||
|
orderInfos = new IExchange.OrderInfo[](numOrders);
|
||||||
|
for (uint256 i = 0; i < numOrders; i++) {
|
||||||
|
orderInfos[i] = IExchange(EXCHANGE_ADDRESS).getOrderInfo(orders[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleSells(
|
||||||
|
address[] memory sources,
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[][] memory makerTokenAmountsBySource)
|
||||||
|
{
|
||||||
|
uint256 numSources = sources.length;
|
||||||
|
makerTokenAmountsBySource = new uint256[][](numSources);
|
||||||
|
for (uint256 i = 0; i < numSources; i++) {
|
||||||
|
makerTokenAmountsBySource[i] = _sampleSellSource(
|
||||||
|
sources[i],
|
||||||
|
takerToken,
|
||||||
|
makerToken,
|
||||||
|
takerTokenAmounts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleBuys(
|
||||||
|
address[] memory sources,
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[][] memory takerTokenAmountsBySource)
|
||||||
|
{
|
||||||
|
uint256 numSources = sources.length;
|
||||||
|
takerTokenAmountsBySource = new uint256[][](numSources);
|
||||||
|
for (uint256 i = 0; i < numSources; i++) {
|
||||||
|
takerTokenAmountsBySource[i] = _sampleBuySource(
|
||||||
|
sources[i],
|
||||||
|
takerToken,
|
||||||
|
makerToken,
|
||||||
|
makerTokenAmounts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleSellFromKyberNetwork(
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
|
{
|
||||||
|
address _takerToken = takerToken == WETH_ADDRESS ? KYBER_ETH_ADDRESS : takerToken;
|
||||||
|
address _makerToken = makerToken == WETH_ADDRESS ? KYBER_ETH_ADDRESS : makerToken;
|
||||||
|
uint256 takerTokenDecimals = LibERC20Token(takerToken).decimals();
|
||||||
|
uint256 makerTokenDecimals = LibERC20Token(makerToken).decimals();
|
||||||
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
(uint256 rate,) = IKyberNetwork(KYBER_NETWORK_PROXY_ADDRESS).getExpectedRate(
|
||||||
|
_takerToken,
|
||||||
|
_makerToken,
|
||||||
|
takerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
makerTokenAmounts[i] =
|
||||||
|
rate *
|
||||||
|
takerTokenAmounts[i] *
|
||||||
|
makerTokenDecimals /
|
||||||
|
(10 ** 18 * takerTokenDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleSellFromEth2Dai(
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
makerTokenAmounts[i] = IEth2Dai(ETH2DAI_ADDRESS).getBuyAmount(
|
||||||
|
makerToken,
|
||||||
|
takerToken,
|
||||||
|
takerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleBuyFromEth2Dai(
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = makerTokenAmounts.length;
|
||||||
|
takerTokenAmounts = new uint256[](numSamples);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
takerTokenAmounts[i] = IEth2Dai(ETH2DAI_ADDRESS).getPayAmount(
|
||||||
|
takerToken,
|
||||||
|
makerToken,
|
||||||
|
makerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleSellFromUniswap(
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
|
IUniswapExchange takerTokenExchange = takerToken == WETH_ADDRESS ?
|
||||||
|
IUniswapExchange(0) :
|
||||||
|
IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS).getExchange(takerToken);
|
||||||
|
IUniswapExchange makerTokenExchange = makerToken == WETH_ADDRESS ?
|
||||||
|
IUniswapExchange(0) :
|
||||||
|
IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS).getExchange(makerToken);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
if (makerToken == WETH_ADDRESS) {
|
||||||
|
makerTokenAmounts[i] = takerTokenExchange.getTokenToEthInputPrice(
|
||||||
|
takerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
} else if (takerToken == WETH_ADDRESS) {
|
||||||
|
makerTokenAmounts[i] = makerTokenExchange.getEthToTokenInputPrice(
|
||||||
|
takerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
uint256 ethBought = takerTokenExchange.getTokenToEthInputPrice(
|
||||||
|
takerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
makerTokenAmounts[i] = makerTokenExchange.getEthToTokenInputPrice(
|
||||||
|
ethBought
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleBuyFromUniswap(
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = makerTokenAmounts.length;
|
||||||
|
takerTokenAmounts = new uint256[](numSamples);
|
||||||
|
IUniswapExchange takerTokenExchange = takerToken == WETH_ADDRESS ?
|
||||||
|
IUniswapExchange(0) :
|
||||||
|
IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS).getExchange(takerToken);
|
||||||
|
IUniswapExchange makerTokenExchange = makerToken == WETH_ADDRESS ?
|
||||||
|
IUniswapExchange(0) :
|
||||||
|
IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS).getExchange(makerToken);
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
if (makerToken == WETH_ADDRESS) {
|
||||||
|
takerTokenAmounts[i] = takerTokenExchange.getTokenToEthOutputPrice(
|
||||||
|
makerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
} else if (takerToken == WETH_ADDRESS) {
|
||||||
|
takerTokenAmounts[i] = makerTokenExchange.getEthToTokenOutputPrice(
|
||||||
|
makerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
uint256 ethSold = makerTokenExchange.getEthToTokenOutputPrice(
|
||||||
|
makerTokenAmounts[i]
|
||||||
|
);
|
||||||
|
takerTokenAmounts[i] = takerTokenExchange.getTokenToEthOutputPrice(
|
||||||
|
ethSold
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _sampleSellSource(
|
||||||
|
address source,
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
private
|
||||||
|
view
|
||||||
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
|
{
|
||||||
|
if (source == ETH2DAI_ADDRESS) {
|
||||||
|
return sampleSellFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
||||||
|
}
|
||||||
|
if (source == UNISWAP_EXCHANGE_FACTORY_ADDRESS) {
|
||||||
|
return sampleSellFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
||||||
|
}
|
||||||
|
if (source == KYBER_NETWORK_PROXY_ADDRESS) {
|
||||||
|
return sampleSellFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
||||||
|
}
|
||||||
|
revert("UNSUPPORTED_SOURCE");
|
||||||
|
}
|
||||||
|
|
||||||
|
function _sampleBuySource(
|
||||||
|
address source,
|
||||||
|
address takerToken,
|
||||||
|
address makerToken,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
private
|
||||||
|
view
|
||||||
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
|
{
|
||||||
|
if (source == ETH2DAI_ADDRESS) {
|
||||||
|
return sampleBuyFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
||||||
|
}
|
||||||
|
if (source == UNISWAP_EXCHANGE_FACTORY_ADDRESS) {
|
||||||
|
return sampleBuyFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
||||||
|
}
|
||||||
|
revert("UNSUPPORTED_SOURCE");
|
||||||
|
}
|
||||||
|
|
||||||
|
function _assetDataToTokenAddress(bytes memory assetData)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns (address tokenAddress)
|
||||||
|
{
|
||||||
|
require(assetData.length == 36, "INVALID_ASSET_DATA");
|
||||||
|
bytes4 selector;
|
||||||
|
assembly {
|
||||||
|
selector := and(mload(add(assetData, 0x20)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
|
||||||
|
tokenAddress := mload(add(assetData, 0x24))
|
||||||
|
}
|
||||||
|
require(selector == ERC20_PROXY_ID, "UNSUPPORTED_ASSET_PROXY");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "./IExchange.sol";
|
||||||
|
|
||||||
|
|
||||||
|
interface IERC20BridgeSampler {
|
||||||
|
|
||||||
|
/// @dev Query native orders and sample sell orders on multiple DEXes at once.
|
||||||
|
/// @param orders Native orders to query.
|
||||||
|
/// @param sources Address of each DEX. Passing in an unknown DEX will throw.
|
||||||
|
/// @param takerTokenAmounts Taker sell amount for each sample.
|
||||||
|
/// @return orderInfos `OrderInfo`s for each order in `orders`.
|
||||||
|
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
|
||||||
|
/// each taker token amount. First indexed by source index, then sample
|
||||||
|
/// index.
|
||||||
|
function queryOrdersAndSampleSells(
|
||||||
|
IExchange.Order[] calldata orders,
|
||||||
|
address[] calldata sources,
|
||||||
|
uint256[] calldata takerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
IExchange.OrderInfo[] memory orderInfos,
|
||||||
|
uint256[][] memory makerTokenAmountsBySource
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Query native orders and sample buy orders on multiple DEXes at once.
|
||||||
|
/// @param orders Native orders to query.
|
||||||
|
/// @param sources Address of each DEX. Passing in an unknown DEX will throw.
|
||||||
|
/// @param makerTokenAmounts Maker sell amount for each sample.
|
||||||
|
/// @return orderInfos `OrderInfo`s for each order in `orders`.
|
||||||
|
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
|
||||||
|
/// each maker token amount. First indexed by source index, then sample
|
||||||
|
/// index.
|
||||||
|
function queryOrdersAndSampleBuys(
|
||||||
|
IExchange.Order[] calldata orders,
|
||||||
|
address[] calldata sources,
|
||||||
|
uint256[] calldata makerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
IExchange.OrderInfo[] memory orderInfos,
|
||||||
|
uint256[][] memory makerTokenAmountsBySource
|
||||||
|
);
|
||||||
|
}
|
21
contracts/erc20-bridge-sampler/contracts/src/IEth2Dai.sol
Normal file
21
contracts/erc20-bridge-sampler/contracts/src/IEth2Dai.sol
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
|
||||||
|
contract IEth2Dai {
|
||||||
|
function getBuyAmount(
|
||||||
|
address buyToken,
|
||||||
|
address payToken,
|
||||||
|
uint256 payAmount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 buyAmount);
|
||||||
|
|
||||||
|
function getPayAmount(
|
||||||
|
address payToken,
|
||||||
|
address buyToken,
|
||||||
|
uint256 buyAmount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 payAmount);
|
||||||
|
}
|
32
contracts/erc20-bridge-sampler/contracts/src/IExchange.sol
Normal file
32
contracts/erc20-bridge-sampler/contracts/src/IExchange.sol
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
interface IExchange {
|
||||||
|
struct Order {
|
||||||
|
address makerAddress;
|
||||||
|
address takerAddress;
|
||||||
|
address feeRecipientAddress;
|
||||||
|
address senderAddress;
|
||||||
|
uint256 makerAssetAmount;
|
||||||
|
uint256 takerAssetAmount;
|
||||||
|
uint256 makerFee;
|
||||||
|
uint256 takerFee;
|
||||||
|
uint256 expirationTimeSeconds;
|
||||||
|
uint256 salt;
|
||||||
|
bytes makerAssetData;
|
||||||
|
bytes takerAssetData;
|
||||||
|
// bytes makerFeeAssetData;
|
||||||
|
// bytes takerFeeAssetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OrderInfo {
|
||||||
|
uint8 orderStatus;
|
||||||
|
bytes32 orderHash;
|
||||||
|
uint256 orderTakerAssetFilledAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrderInfo(Order calldata order)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (OrderInfo memory orderInfo);
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
|
||||||
|
contract IKyberNetwork {
|
||||||
|
function getExpectedRate(
|
||||||
|
address fromToken,
|
||||||
|
address toToken,
|
||||||
|
uint256 fromAmount
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256 expectedRate, uint256 slippageRate);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
|
||||||
|
interface IUniswapExchange {
|
||||||
|
function getEthToTokenInputPrice(
|
||||||
|
uint256 ethSold
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 tokensBought);
|
||||||
|
|
||||||
|
function getEthToTokenOutputPrice(
|
||||||
|
uint256 tokensBought
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 ethSold);
|
||||||
|
|
||||||
|
function getTokenToEthInputPrice(
|
||||||
|
uint256 tokensSold
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 ethBought);
|
||||||
|
|
||||||
|
function getTokenToEthOutputPrice(
|
||||||
|
uint256 ethBought
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 tokensSold);
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
pragma solidity ^0.5;
|
||||||
|
|
||||||
|
|
||||||
|
library LibERC20Token {
|
||||||
|
|
||||||
|
/// @dev Calls `IERC20Token(token).approve()`.
|
||||||
|
/// Reverts if `false` is returned or if the return
|
||||||
|
/// data length is nonzero and not 32 bytes.
|
||||||
|
/// @param token The address of the token contract.
|
||||||
|
/// @param spender The address that receives an allowance.
|
||||||
|
/// @param allowance The allowance to set.
|
||||||
|
function approve(
|
||||||
|
address token,
|
||||||
|
address spender,
|
||||||
|
uint256 allowance
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
|
0x095ea7b3,
|
||||||
|
spender,
|
||||||
|
allowance
|
||||||
|
);
|
||||||
|
_callWithOptionalBooleanResult(token, callData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls `IERC20Token(token).transfer()`.
|
||||||
|
/// Reverts if `false` is returned or if the return
|
||||||
|
/// data length is nonzero and not 32 bytes.
|
||||||
|
/// @param token The address of the token contract.
|
||||||
|
/// @param to The address that receives the tokens
|
||||||
|
/// @param amount Number of tokens to transfer.
|
||||||
|
function transfer(
|
||||||
|
address token,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
|
0xa9059cbb,
|
||||||
|
to,
|
||||||
|
amount
|
||||||
|
);
|
||||||
|
_callWithOptionalBooleanResult(token, callData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls `IERC20Token(token).transferFrom()`.
|
||||||
|
/// Reverts if `false` is returned or if the return
|
||||||
|
/// data length is nonzero and not 32 bytes.
|
||||||
|
/// @param token The address of the token contract.
|
||||||
|
/// @param from The owner of the tokens.
|
||||||
|
/// @param to The address that receives the tokens
|
||||||
|
/// @param amount Number of tokens to transfer.
|
||||||
|
function transferFrom(
|
||||||
|
address token,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
|
0x23b872dd,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
amount
|
||||||
|
);
|
||||||
|
_callWithOptionalBooleanResult(token, callData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Executes a call on address `target` with calldata `callData`
|
||||||
|
/// and asserts that either nothing was returned or a single boolean
|
||||||
|
/// was returned equal to `true`.
|
||||||
|
/// @param target The call target.
|
||||||
|
/// @param callData The abi-encoded call data.
|
||||||
|
function _callWithOptionalBooleanResult(
|
||||||
|
address target,
|
||||||
|
bytes memory callData
|
||||||
|
)
|
||||||
|
private
|
||||||
|
{
|
||||||
|
(bool didSucceed, bytes memory resultData) = target.call(callData);
|
||||||
|
if (didSucceed) {
|
||||||
|
if (resultData.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resultData.length == 32) {
|
||||||
|
uint256 result;
|
||||||
|
assembly { result := mload(add(resultData, 0x20)) }
|
||||||
|
if (result == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assembly { revert(add(resultData, 0x20), mload(resultData)) }
|
||||||
|
}
|
||||||
|
}
|
91
contracts/erc20-bridge-sampler/package.json
Normal file
91
contracts/erc20-bridge-sampler/package.json
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||||
|
"version": "1.0.0-beta.1",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.12"
|
||||||
|
},
|
||||||
|
"description": "Sampler contracts for the 0x asset-swapper",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn pre_build && tsc -b",
|
||||||
|
"build:ci": "yarn build",
|
||||||
|
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||||
|
"test": "yarn run_mocha",
|
||||||
|
"rebuild_and_test": "run-s build test",
|
||||||
|
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||||
|
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||||
|
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||||
|
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||||
|
"compile": "sol-compiler",
|
||||||
|
"watch": "sol-compiler -w",
|
||||||
|
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||||
|
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||||
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"coverage:report:text": "istanbul report text",
|
||||||
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"coverage:report:lcov": "istanbul report lcov",
|
||||||
|
"test:circleci": "yarn test",
|
||||||
|
"contracts:gen": "contracts-gen generate",
|
||||||
|
"contracts:copy": "contracts-gen copy",
|
||||||
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||||
|
"compile:truffle": "truffle compile"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"publicInterfaceContracts": "ERC20BridgeSampler",
|
||||||
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
|
"abis": "./test/generated-artifacts/@(Exchange|IAssetProxy|IAssetProxyDispatcher|IEIP1271Data|IEIP1271Wallet|IExchange|IExchangeCore|IMatchOrders|IProtocolFees|ISignatureValidator|ITransactions|ITransferSimulator|IWallet|IWrapperFunctions|IsolatedExchange|LibExchangeRichErrorDecoder|MixinAssetProxyDispatcher|MixinExchangeCore|MixinMatchOrders|MixinProtocolFees|MixinSignatureValidator|MixinTransactions|MixinTransferSimulator|MixinWrapperFunctions|ReentrancyTester|TestAssetProxyDispatcher|TestExchangeInternals|TestFillRounding|TestLibExchangeRichErrorDecoder|TestProtocolFeeCollector|TestProtocolFees|TestProtocolFeesReceiver|TestSignatureValidator|TestTransactions|TestValidatorWallet|TestWrapperFunctions).json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@0x/abi-gen": "^4.4.0-beta.1",
|
||||||
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.1",
|
||||||
|
"@0x/contracts-erc20": "^2.3.0-beta.1",
|
||||||
|
"@0x/contracts-exchange-libs": "^3.1.0-beta.1",
|
||||||
|
"@0x/contracts-gen": "^1.1.0-beta.1",
|
||||||
|
"@0x/contracts-test-utils": "^3.2.0-beta.1",
|
||||||
|
"@0x/contracts-utils": "^3.3.0-beta.1",
|
||||||
|
"@0x/dev-utils": "^2.4.0-beta.1",
|
||||||
|
"@0x/sol-compiler": "^3.2.0-beta.1",
|
||||||
|
"@0x/tslint-config": "^3.1.0-beta.1",
|
||||||
|
"@0x/web3-wrapper": "^6.1.0-beta.1",
|
||||||
|
"@types/lodash": "4.14.104",
|
||||||
|
"@types/mocha": "^5.2.7",
|
||||||
|
"@types/node": "*",
|
||||||
|
"chai": "^4.0.1",
|
||||||
|
"chai-as-promised": "^7.1.0",
|
||||||
|
"chai-bignumber": "^3.0.0",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"make-promises-safe": "^1.1.0",
|
||||||
|
"mocha": "^6.2.0",
|
||||||
|
"npm-run-all": "^4.1.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"solhint": "^1.4.1",
|
||||||
|
"truffle": "^5.0.32",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"typescript": "3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@0x/base-contract": "^5.5.0-beta.1",
|
||||||
|
"@0x/types": "^2.5.0-beta.1",
|
||||||
|
"@0x/typescript-typings": "^4.4.0-beta.1",
|
||||||
|
"@0x/utils": "^4.6.0-beta.1",
|
||||||
|
"ethereum-types": "^2.2.0-beta.1",
|
||||||
|
"lodash": "^4.17.11"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
0
contracts/erc20-bridge-sampler/src/.gitkeep
Normal file
0
contracts/erc20-bridge-sampler/src/.gitkeep
Normal file
0
contracts/erc20-bridge-sampler/test/.gitkeep
Normal file
0
contracts/erc20-bridge-sampler/test/.gitkeep
Normal file
96
contracts/erc20-bridge-sampler/truffle-config.js
Normal file
96
contracts/erc20-bridge-sampler/truffle-config.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Use this file to configure your truffle project. It's seeded with some
|
||||||
|
* common settings for different networks and features like migrations,
|
||||||
|
* compilation and testing. Uncomment the ones you need or modify
|
||||||
|
* them to suit your project as necessary.
|
||||||
|
*
|
||||||
|
* More information about configuration can be found at:
|
||||||
|
*
|
||||||
|
* truffleframework.com/docs/advanced/configuration
|
||||||
|
*
|
||||||
|
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||||
|
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||||
|
* are available for free at: infura.io/register.
|
||||||
|
*
|
||||||
|
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||||
|
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||||
|
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||||
|
// const infuraKey = "fj4jll3k.....";
|
||||||
|
//
|
||||||
|
// const fs = require('fs');
|
||||||
|
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Networks define how you connect to your ethereum client and let you set the
|
||||||
|
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||||
|
* will spin up a development blockchain for you on port 9545 when you
|
||||||
|
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||||
|
* network from the command line, e.g
|
||||||
|
*
|
||||||
|
* $ truffle test --network <network-name>
|
||||||
|
*/
|
||||||
|
|
||||||
|
networks: {
|
||||||
|
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||||
|
// if it's defined here and no other network is specified at the command line.
|
||||||
|
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||||
|
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||||
|
// options below to some value.
|
||||||
|
//
|
||||||
|
// development: {
|
||||||
|
// host: "127.0.0.1", // Localhost (default: none)
|
||||||
|
// port: 8545, // Standard Ethereum port (default: none)
|
||||||
|
// network_id: "*", // Any network (default: none)
|
||||||
|
// },
|
||||||
|
// Another network with more advanced options...
|
||||||
|
// advanced: {
|
||||||
|
// port: 8777, // Custom port
|
||||||
|
// network_id: 1342, // Custom network
|
||||||
|
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||||
|
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||||
|
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||||
|
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||||
|
// },
|
||||||
|
// Useful for deploying to a public network.
|
||||||
|
// NB: It's important to wrap the provider as a function.
|
||||||
|
// ropsten: {
|
||||||
|
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||||
|
// network_id: 3, // Ropsten's id
|
||||||
|
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||||
|
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||||
|
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||||
|
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||||
|
// },
|
||||||
|
// Useful for private networks
|
||||||
|
// private: {
|
||||||
|
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||||
|
// network_id: 2111, // This network is yours, in the cloud.
|
||||||
|
// production: true // Treats this network as if it was a public net. (default: false)
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Set default mocha options here, use special reporters etc.
|
||||||
|
mocha: {
|
||||||
|
// timeout: 100000
|
||||||
|
},
|
||||||
|
|
||||||
|
// Configure your compilers
|
||||||
|
compilers: {
|
||||||
|
solc: {
|
||||||
|
version: '0.5.9',
|
||||||
|
settings: {
|
||||||
|
evmVersion: 'constantinople',
|
||||||
|
optimizer: {
|
||||||
|
enabled: true,
|
||||||
|
runs: 1000000,
|
||||||
|
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
46
contracts/erc20-bridge-sampler/tsconfig.json
Normal file
46
contracts/erc20-bridge-sampler/tsconfig.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||||
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
|
"files": [
|
||||||
|
"generated-artifacts/Exchange.json",
|
||||||
|
"generated-artifacts/IExchange.json",
|
||||||
|
"test/generated-artifacts/Exchange.json",
|
||||||
|
"test/generated-artifacts/IAssetProxy.json",
|
||||||
|
"test/generated-artifacts/IAssetProxyDispatcher.json",
|
||||||
|
"test/generated-artifacts/IEIP1271Data.json",
|
||||||
|
"test/generated-artifacts/IEIP1271Wallet.json",
|
||||||
|
"test/generated-artifacts/IExchange.json",
|
||||||
|
"test/generated-artifacts/IExchangeCore.json",
|
||||||
|
"test/generated-artifacts/IMatchOrders.json",
|
||||||
|
"test/generated-artifacts/IProtocolFees.json",
|
||||||
|
"test/generated-artifacts/ISignatureValidator.json",
|
||||||
|
"test/generated-artifacts/ITransactions.json",
|
||||||
|
"test/generated-artifacts/ITransferSimulator.json",
|
||||||
|
"test/generated-artifacts/IWallet.json",
|
||||||
|
"test/generated-artifacts/IWrapperFunctions.json",
|
||||||
|
"test/generated-artifacts/IsolatedExchange.json",
|
||||||
|
"test/generated-artifacts/LibExchangeRichErrorDecoder.json",
|
||||||
|
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||||
|
"test/generated-artifacts/MixinExchangeCore.json",
|
||||||
|
"test/generated-artifacts/MixinMatchOrders.json",
|
||||||
|
"test/generated-artifacts/MixinProtocolFees.json",
|
||||||
|
"test/generated-artifacts/MixinSignatureValidator.json",
|
||||||
|
"test/generated-artifacts/MixinTransactions.json",
|
||||||
|
"test/generated-artifacts/MixinTransferSimulator.json",
|
||||||
|
"test/generated-artifacts/MixinWrapperFunctions.json",
|
||||||
|
"test/generated-artifacts/ReentrancyTester.json",
|
||||||
|
"test/generated-artifacts/TestAssetProxyDispatcher.json",
|
||||||
|
"test/generated-artifacts/TestExchangeInternals.json",
|
||||||
|
"test/generated-artifacts/TestFillRounding.json",
|
||||||
|
"test/generated-artifacts/TestLibExchangeRichErrorDecoder.json",
|
||||||
|
"test/generated-artifacts/TestProtocolFeeCollector.json",
|
||||||
|
"test/generated-artifacts/TestProtocolFees.json",
|
||||||
|
"test/generated-artifacts/TestProtocolFeesReceiver.json",
|
||||||
|
"test/generated-artifacts/TestSignatureValidator.json",
|
||||||
|
"test/generated-artifacts/TestTransactions.json",
|
||||||
|
"test/generated-artifacts/TestValidatorWallet.json",
|
||||||
|
"test/generated-artifacts/TestWrapperFunctions.json"
|
||||||
|
],
|
||||||
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
}
|
10
contracts/erc20-bridge-sampler/tslint.json
Normal file
10
contracts/erc20-bridge-sampler/tslint.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": ["@0x/tslint-config"],
|
||||||
|
"rules": {
|
||||||
|
"custom-no-magic-numbers": false,
|
||||||
|
"max-file-line-count": false
|
||||||
|
},
|
||||||
|
"linterOptions": {
|
||||||
|
"exclude": ["src/artifacts.ts"]
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
|
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
|
||||||
"pr": 2330
|
"pr": 2330
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `decimals()` to `LibERC20Token`.",
|
||||||
|
"pr": "TODO"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timestamp": 1574030254
|
"timestamp": 1574030254
|
||||||
|
@ -24,6 +24,7 @@ import "../src/interfaces/IERC20Token.sol";
|
|||||||
|
|
||||||
|
|
||||||
library LibERC20Token {
|
library LibERC20Token {
|
||||||
|
bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
|
||||||
|
|
||||||
/// @dev Calls `IERC20Token(token).approve()`.
|
/// @dev Calls `IERC20Token(token).approve()`.
|
||||||
/// Reverts if `false` is returned or if the return
|
/// Reverts if `false` is returned or if the return
|
||||||
@ -91,6 +92,21 @@ library LibERC20Token {
|
|||||||
_callWithOptionalBooleanResult(token, callData);
|
_callWithOptionalBooleanResult(token, callData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Retrieves the number of decimals for a token.
|
||||||
|
/// Returns `18` if the call reverts.
|
||||||
|
/// @return The number of decimals places for the token.
|
||||||
|
function decimals(address token)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint8 tokenDecimals)
|
||||||
|
{
|
||||||
|
tokenDecimals = 18;
|
||||||
|
(bool didSucceed, bytes memory resultData) = token.staticcall(DECIMALS_CALL_DATA);
|
||||||
|
if (didSucceed && resultData.length == 32) {
|
||||||
|
tokenDecimals = uint8(LibBytes.readUint256(resultData, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Executes a call on address `target` with calldata `callData`
|
/// @dev Executes a call on address `target` with calldata `callData`
|
||||||
/// and asserts that either nothing was returned or a single boolean
|
/// and asserts that either nothing was returned or a single boolean
|
||||||
/// was returned equal to `true`.
|
/// was returned equal to `true`.
|
||||||
|
@ -69,4 +69,16 @@ contract TestLibERC20Token {
|
|||||||
target.setBehavior(shouldRevert, revertData, returnData);
|
target.setBehavior(shouldRevert, revertData, returnData);
|
||||||
LibERC20Token.transferFrom(address(target), from, to, amount);
|
LibERC20Token.transferFrom(address(target), from, to, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testDecimals(
|
||||||
|
bool shouldRevert,
|
||||||
|
bytes calldata revertData,
|
||||||
|
bytes calldata returnData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint8)
|
||||||
|
{
|
||||||
|
target.setBehavior(shouldRevert, revertData, returnData);
|
||||||
|
return LibERC20Token.decimals(address(target));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,14 @@ contract TestLibERC20TokenTarget {
|
|||||||
_execute();
|
_execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function decimals()
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint8)
|
||||||
|
{
|
||||||
|
_execute();
|
||||||
|
}
|
||||||
|
|
||||||
function _execute() private view {
|
function _execute() private view {
|
||||||
if (_shouldRevert) {
|
if (_shouldRevert) {
|
||||||
bytes memory revertData = _revertData;
|
bytes memory revertData = _revertData;
|
||||||
|
@ -16,6 +16,7 @@ import { artifacts } from './artifacts';
|
|||||||
blockchainTests('LibERC20Token', env => {
|
blockchainTests('LibERC20Token', env => {
|
||||||
let testContract: TestLibERC20TokenContract;
|
let testContract: TestLibERC20TokenContract;
|
||||||
const REVERT_STRING = 'WHOOPSIE';
|
const REVERT_STRING = 'WHOOPSIE';
|
||||||
|
const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
|
||||||
const ENCODED_TRUE = hexLeftPad(1);
|
const ENCODED_TRUE = hexLeftPad(1);
|
||||||
const ENCODED_FALSE = hexLeftPad(0);
|
const ENCODED_FALSE = hexLeftPad(0);
|
||||||
const ENCODED_TWO = hexLeftPad(2);
|
const ENCODED_TWO = hexLeftPad(2);
|
||||||
@ -31,16 +32,12 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
function encodeRevert(message: string): string {
|
|
||||||
return new StringRevertError(message).encode();
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('approve()', () => {
|
describe('approve()', () => {
|
||||||
it('calls the target with the correct arguments', async () => {
|
it('calls the target with the correct arguments', async () => {
|
||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
const { logs } = await testContract
|
const { logs } = await testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), ENCODED_TRUE, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
expect(logs).to.be.length(1);
|
expect(logs).to.be.length(1);
|
||||||
verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
|
verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
|
||||||
@ -50,7 +47,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
await testContract
|
await testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), ENCODED_TRUE, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -58,7 +55,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
await testContract
|
await testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), constants.NULL_BYTES, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, constants.NULL_BYTES, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,7 +63,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), ENCODED_FALSE, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, ENCODED_FALSE, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -76,7 +73,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), ENCODED_TWO, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, ENCODED_TWO, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -86,7 +83,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), ENCODED_SHORT_TRUE, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -96,7 +93,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testApprove(false, encodeRevert(REVERT_STRING), ENCODED_LONG_TRUE, spender, allowance)
|
.testApprove(false, ENCODED_REVERT, ENCODED_LONG_TRUE, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -106,7 +103,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const spender = randomAddress();
|
const spender = randomAddress();
|
||||||
const allowance = getRandomInteger(0, 100e18);
|
const allowance = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testApprove(true, encodeRevert(REVERT_STRING), ENCODED_TRUE, spender, allowance)
|
.testApprove(true, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
return expect(tx).to.revertWith(REVERT_STRING);
|
return expect(tx).to.revertWith(REVERT_STRING);
|
||||||
});
|
});
|
||||||
@ -126,7 +123,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const { logs } = await testContract
|
const { logs } = await testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), ENCODED_TRUE, to, amount)
|
.testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
expect(logs).to.be.length(1);
|
expect(logs).to.be.length(1);
|
||||||
verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
|
verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
|
||||||
@ -136,7 +133,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
await testContract
|
await testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), ENCODED_TRUE, to, amount)
|
.testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -144,7 +141,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
await testContract
|
await testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), constants.NULL_BYTES, to, amount)
|
.testTransfer(false, ENCODED_REVERT, constants.NULL_BYTES, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -152,7 +149,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), ENCODED_FALSE, to, amount)
|
.testTransfer(false, ENCODED_REVERT, ENCODED_FALSE, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -162,7 +159,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), ENCODED_TWO, to, amount)
|
.testTransfer(false, ENCODED_REVERT, ENCODED_TWO, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -172,7 +169,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), ENCODED_SHORT_TRUE, to, amount)
|
.testTransfer(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -182,7 +179,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransfer(false, encodeRevert(REVERT_STRING), ENCODED_LONG_TRUE, to, amount)
|
.testTransfer(false, ENCODED_REVERT, ENCODED_LONG_TRUE, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -192,7 +189,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransfer(true, encodeRevert(REVERT_STRING), ENCODED_TRUE, to, amount)
|
.testTransfer(true, ENCODED_REVERT, ENCODED_TRUE, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
return expect(tx).to.revertWith(REVERT_STRING);
|
return expect(tx).to.revertWith(REVERT_STRING);
|
||||||
});
|
});
|
||||||
@ -213,7 +210,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const { logs } = await testContract
|
const { logs } = await testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), ENCODED_TRUE, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
expect(logs).to.be.length(1);
|
expect(logs).to.be.length(1);
|
||||||
verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
|
verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
|
||||||
@ -224,7 +221,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
await testContract
|
await testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), ENCODED_TRUE, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -233,7 +230,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
await testContract
|
await testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), constants.NULL_BYTES, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, constants.NULL_BYTES, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -242,7 +239,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), ENCODED_FALSE, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, ENCODED_FALSE, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -253,7 +250,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), ENCODED_TWO, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TWO, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -264,7 +261,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), ENCODED_SHORT_TRUE, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -275,7 +272,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransferFrom(false, encodeRevert(REVERT_STRING), ENCODED_LONG_TRUE, owner, to, amount)
|
.testTransferFrom(false, ENCODED_REVERT, ENCODED_LONG_TRUE, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
@ -286,7 +283,7 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
const to = randomAddress();
|
const to = randomAddress();
|
||||||
const amount = getRandomInteger(0, 100e18);
|
const amount = getRandomInteger(0, 100e18);
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.testTransferFrom(true, encodeRevert(REVERT_STRING), ENCODED_TRUE, owner, to, amount)
|
.testTransferFrom(true, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
return expect(tx).to.revertWith(REVERT_STRING);
|
return expect(tx).to.revertWith(REVERT_STRING);
|
||||||
});
|
});
|
||||||
@ -301,4 +298,39 @@ blockchainTests('LibERC20Token', env => {
|
|||||||
return expect(tx).to.be.rejectedWith('revert');
|
return expect(tx).to.be.rejectedWith('revert');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('decimals()', () => {
|
||||||
|
const DEFAULT_DECIMALS = 18;
|
||||||
|
const ENCODED_ZERO = hexLeftPad(0);
|
||||||
|
const ENCODED_SHORT_ZERO = hexLeftPad(0, 31);
|
||||||
|
const ENCODED_LONG_ZERO = hexLeftPad(0, 33);
|
||||||
|
const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
|
||||||
|
|
||||||
|
it('returns the number of decimals defined by the token', async () => {
|
||||||
|
const decimals = randomDecimals();
|
||||||
|
const encodedDecimals = hexLeftPad(decimals);
|
||||||
|
const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
|
||||||
|
return expect(result).to.bignumber.eq(decimals);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 0 if the token returns 0', async () => {
|
||||||
|
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_ZERO).callAsync();
|
||||||
|
return expect(result).to.bignumber.eq(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 18 if the token returns less than 32 bytes', async () => {
|
||||||
|
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_SHORT_ZERO).callAsync();
|
||||||
|
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 18 if the token returns greater than 32 bytes', async () => {
|
||||||
|
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_LONG_ZERO).callAsync();
|
||||||
|
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 18 if the token reverts', async () => {
|
||||||
|
const result = await testContract.testDecimals(true, ENCODED_REVERT, ENCODED_ZERO).callAsync();
|
||||||
|
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user