@0x/contracts-asset-proxy: Rename IERC20Bridge.transfer() -> IERC20Bridge.withdrawTo().

`@0x/contracts-asset-proxy`: Make `bridgeData` last parameter in `IERC20Bridge.withdrawTo()`.
`@0x/contracts-asset-proxy`: Reuse `PROXY_ID` as `BRIDGE_SUCCESS`.
This commit is contained in:
Lawrence Forman 2019-09-29 17:08:43 -04:00
parent b728d13d8c
commit b50e26dc2a
5 changed files with 67 additions and 31 deletions

View File

@ -34,9 +34,7 @@ contract ERC20BridgeProxy is
using LibBytes for bytes; using LibBytes for bytes;
using LibSafeMath for uint256; using LibSafeMath for uint256;
// @dev Result of a successful bridge call. // @dev Id of this proxy. Also the result of a successful bridge call.
bytes4 constant public BRIDGE_SUCCESS = 0xb5d40d78;
// @dev Id of this proxy.
// bytes4(keccak256("ERC20BridgeProxy(address,address,bytes)")) // bytes4(keccak256("ERC20BridgeProxy(address,address,bytes)"))
bytes4 constant private PROXY_ID = 0x37708e9b; bytes4 constant private PROXY_ID = 0x37708e9b;
@ -75,15 +73,15 @@ contract ERC20BridgeProxy is
uint256 balanceBefore = balanceOf(tokenAddress, to); uint256 balanceBefore = balanceOf(tokenAddress, to);
// Call the bridge, who should transfer `amount` of `tokenAddress` to // Call the bridge, who should transfer `amount` of `tokenAddress` to
// `to`. // `to`.
bytes4 success = IERC20Bridge(bridgeAddress).transfer( bytes4 success = IERC20Bridge(bridgeAddress).withdrawTo(
bridgeData,
tokenAddress, tokenAddress,
from, from,
to, to,
amount amount,
bridgeData
); );
// Bridge must return the magic bytes to indicate success. // Bridge must return the proxy ID to indicate success.
require(success == BRIDGE_SUCCESS, "BRIDGE_FAILED"); require(success == PROXY_ID, "BRIDGE_FAILED");
// Ensure that the balance of `to` has increased by at least `amount`. // Ensure that the balance of `to` has increased by at least `amount`.
require( require(
balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to), balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to),
@ -109,9 +107,9 @@ contract ERC20BridgeProxy is
view view
returns (uint256 balance) returns (uint256 balance)
{ {
(address tokenAddress, ,) = abi.decode( (address tokenAddress) = abi.decode(
assetData.sliceDestructive(4, assetData.length), assetData.sliceDestructive(4, assetData.length),
(address, address, bytes) (address)
); );
return balanceOf(tokenAddress, owner); return balanceOf(tokenAddress, owner);
} }

View File

@ -0,0 +1,30 @@
/*
Copyright 2019 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.5.9;
pragma experimental ABIEncoderV2;
import "../interfaces/IERC20Bridge.sol";
contract ERC20Bridge is
IERC20Bridge
{
// @dev Result of a successful bridge call.
bytes4 constant internal BRIDGE_SUCCESS = 0x37708e9b;
}

View File

@ -19,21 +19,21 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
contract IERC20Bridge { interface IERC20Bridge {
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`. /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
/// @param tokenAddress The address of the ERC20 token to transfer. /// @param tokenAddress The address of the ERC20 token to transfer.
/// @param from Address to transfer asset from. /// @param from Address to transfer asset from.
/// @param to Address to transfer asset to. /// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer. /// @param amount Amount of asset to transfer.
/// @return success The magic bytes `0xb5d40d78` if successful. /// @param bridgeData Arbitrary asset data needed by the bridge contract.
function transfer( /// @return success The magic bytes `0x37708e9b` if successful.
bytes calldata bridgeData, function withdrawTo(
address tokenAddress, address tokenAddress,
address from, address from,
address to, address to,
uint256 amount uint256 amount,
bytes calldata bridgeData
) )
external external
returns (bytes4 success); returns (bytes4 success);

View File

@ -19,7 +19,7 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "../src/interfaces/IERC20Bridge.sol"; import "../src/bridges/ERC20Bridge.sol";
/// @dev Test bridge token /// @dev Test bridge token
@ -50,16 +50,16 @@ contract TestERC20BridgeToken {
/// @dev Test bridge contract. /// @dev Test bridge contract.
contract TestERC20Bridge is contract TestERC20Bridge is
IERC20Bridge ERC20Bridge
{ {
TestERC20BridgeToken public testToken; TestERC20BridgeToken public testToken;
event BridgeTransfer( event BridgeWithdrawTo(
bytes bridgeData,
address tokenAddress, address tokenAddress,
address from, address from,
address to, address to,
uint256 amount uint256 amount,
bytes bridgeData
); );
constructor() public { constructor() public {
@ -72,22 +72,22 @@ contract TestERC20Bridge is
testToken.setBalance(owner, balance); testToken.setBalance(owner, balance);
} }
function transfer( function withdrawTo(
bytes calldata bridgeData,
address tokenAddress, address tokenAddress,
address from, address from,
address to, address to,
uint256 amount uint256 amount,
bytes calldata bridgeData
) )
external external
returns (bytes4) returns (bytes4)
{ {
emit BridgeTransfer( emit BridgeWithdrawTo(
bridgeData,
tokenAddress, tokenAddress,
from, from,
to, to,
amount amount,
bridgeData
); );
// Unpack the bridgeData. // Unpack the bridgeData.
( (

View File

@ -16,12 +16,13 @@ import * as _ from 'lodash';
import { import {
artifacts, artifacts,
ERC20BridgeProxyContract, ERC20BridgeProxyContract,
TestERC20BridgeBridgeTransferEventArgs, TestERC20BridgeBridgeWithdrawToEventArgs,
TestERC20BridgeContract, TestERC20BridgeContract,
} from '../src'; } from '../src';
blockchainTests.resets('ERC20BridgeProxy unit tests', env => { blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad('0xb5d40d78'); const PROXY_ID = '0xb5d40d78';
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID);
let owner: string; let owner: string;
let badCaller: string; let badCaller: string;
let assetProxy: ERC20BridgeProxyContract; let assetProxy: ERC20BridgeProxyContract;
@ -162,12 +163,12 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
const opts = createTransferFromOpts(); const opts = createTransferFromOpts();
const logs = await transferFromAsync(opts); const logs = await transferFromAsync(opts);
expect(logs.length).to.eq(1); expect(logs.length).to.eq(1);
const args = logs[0].args as TestERC20BridgeBridgeTransferEventArgs; const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs;
expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress); expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
expect(args.from).to.eq(opts.from); expect(args.from).to.eq(opts.from);
expect(args.to).to.eq(opts.to); expect(args.to).to.eq(opts.to);
expect(args.amount).to.bignumber.eq(opts.amount); expect(args.amount).to.bignumber.eq(opts.amount);
expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
}); });
it('fails if not called by an authorized address', async () => { it('fails if not called by an authorized address', async () => {
@ -287,4 +288,11 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
expect(actualBalance).to.bignumber.eq(balance); expect(actualBalance).to.bignumber.eq(balance);
}); });
}); });
describe('getProxyId()', () => {
it('returns the correct proxy ID', async () => {
const proxyId = await assetProxy.getProxyId.callAsync();
expect(proxyId).to.eq(PROXY_ID);
});
});
}); });