@0x/contracts-asset-proxy
: Emit ERC20BridgeTransfer
events in bridges.
This commit is contained in:
parent
b604e2bd4e
commit
3f51b9322f
@ -3,7 +3,12 @@
|
||||
"version": "3.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use `approveIfBelowMax()` in DEX bridges for for approvals."
|
||||
"note": "Use `approveIfBelowMax()` in DEX bridges for for approvals.",
|
||||
"pr": 2512
|
||||
},
|
||||
{
|
||||
"note": "Emit `ERC20BridgeTransfer` events in bridges.",
|
||||
"pr": 2512
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -70,6 +70,16 @@ contract ChaiBridge is
|
||||
// This will never fail if the `draw` call was successful
|
||||
IERC20Token(_getDaiAddress()).transfer(to, amount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
address(this),
|
||||
_getChaiAddress(),
|
||||
_getDaiAddress(),
|
||||
// draw() can change the rate so this is tricky to compute.
|
||||
0,
|
||||
amount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -35,18 +35,26 @@ contract CurveBridge is
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct CurveBridgeData {
|
||||
address curveAddress;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
int128 version;
|
||||
}
|
||||
|
||||
/// @dev Callback for `ICurve`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI, USDC) to the Curve contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@ -55,32 +63,32 @@ contract CurveBridge is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
(address curveAddress, int128 fromCoinIdx, int128 toCoinIdx, int128 version) = abi.decode(bridgeData, (address, int128, int128, int128));
|
||||
ICurve exchange = ICurve(curveAddress);
|
||||
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
|
||||
|
||||
address fromTokenAddress = exchange.underlying_coins(fromCoinIdx);
|
||||
address fromTokenAddress = ICurve(data.curveAddress).underlying_coins(data.fromCoinIdx);
|
||||
require(toTokenAddress != fromTokenAddress, "CurveBridge/INVALID_PAIR");
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelowMax(fromTokenAddress, address(exchange));
|
||||
LibERC20Token.approveIfBelowMax(fromTokenAddress, data.curveAddress);
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
if (version == 0) {
|
||||
exchange.exchange_underlying(
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
if (data.version == 0) {
|
||||
ICurve(data.curveAddress).exchange_underlying(
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
fromTokenBalance,
|
||||
// min dy
|
||||
amount,
|
||||
// expires
|
||||
block.timestamp + 1
|
||||
);
|
||||
} else {
|
||||
exchange.exchange_underlying(
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
ICurve(data.curveAddress).exchange_underlying(
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
fromTokenBalance,
|
||||
// min dy
|
||||
amount
|
||||
);
|
||||
@ -89,6 +97,16 @@ contract CurveBridge is
|
||||
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
address(this),
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
toTokenBalance,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -44,13 +44,14 @@ contract DydxBridge is
|
||||
/// 5. Withdrawals from dydx are made to the `to` address.
|
||||
/// 6. Calling this function must always withdraw at least `amount`,
|
||||
/// otherwise the `ERC20Bridge` will revert.
|
||||
/// @param toTokenAddress The token to be withdrawn.
|
||||
/// @param from The sender of the tokens and owner of the dydx account.
|
||||
/// @param to The recipient of the tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw.
|
||||
/// @param encodedBridgeData An abi-encoded `BridgeData` struct.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address,
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
@ -81,6 +82,18 @@ contract DydxBridge is
|
||||
|
||||
// Run operation. This will revert on failure.
|
||||
IDydx(_getDydxAddress()).operate(accounts, actions);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
address(this),
|
||||
// The from token isn't necessarily clear since we can have zero
|
||||
// or more deposits.
|
||||
address(0),
|
||||
toTokenAddress,
|
||||
0,
|
||||
amount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -38,13 +38,14 @@ contract Eth2DaiBridge is
|
||||
/// (DAI or WETH) to the Eth2Dai contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (either DAI or WETH).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@ -59,15 +60,27 @@ contract Eth2DaiBridge is
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelowMax(fromTokenAddress, address(exchange));
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = exchange.sellAllAmount(
|
||||
fromTokenAddress,
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
fromTokenBalance,
|
||||
toTokenAddress,
|
||||
amount
|
||||
);
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
address(this),
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -66,13 +66,14 @@ contract KyberBridge is
|
||||
/// to the `KyberNetworkProxy` contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@ -143,6 +144,16 @@ contract KyberBridge is
|
||||
state.weth.deposit.value(boughtAmount)();
|
||||
state.weth.transfer(to, boughtAmount);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
address(this),
|
||||
state.fromTokenAddress == KYBER_ETH_ADDRESS ? address(state.weth) : state.fromTokenAddress,
|
||||
toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -38,10 +38,11 @@ contract UniswapBridge is
|
||||
{
|
||||
// Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
|
||||
// stack overflows.
|
||||
struct WithdrawToState {
|
||||
struct TransferState {
|
||||
IUniswapExchange exchange;
|
||||
uint256 fromTokenBalance;
|
||||
IEtherToken weth;
|
||||
uint256 boughtAmount;
|
||||
}
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
@ -55,13 +56,14 @@ contract UniswapBridge is
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@ -70,7 +72,7 @@ contract UniswapBridge is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// State memory object to avoid stack overflows.
|
||||
WithdrawToState memory state;
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
@ -96,7 +98,7 @@ contract UniswapBridge is
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
// Buy as much of `toTokenAddress` token with ETH as possible and
|
||||
// transfer it to `to`.
|
||||
state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
||||
state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Expires after this block.
|
||||
@ -110,7 +112,7 @@ contract UniswapBridge is
|
||||
// Grant the exchange an allowance.
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress);
|
||||
// Buy as much ETH with `fromTokenAddress` token as possible.
|
||||
uint256 ethBought = state.exchange.tokenToEthSwapInput(
|
||||
state.boughtAmount = state.exchange.tokenToEthSwapInput(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
@ -119,9 +121,9 @@ contract UniswapBridge is
|
||||
block.timestamp
|
||||
);
|
||||
// Wrap the ETH.
|
||||
state.weth.deposit.value(ethBought)();
|
||||
state.weth.deposit.value(state.boughtAmount)();
|
||||
// Transfer the WETH to `to`.
|
||||
IEtherToken(toTokenAddress).transfer(to, ethBought);
|
||||
IEtherToken(toTokenAddress).transfer(to, state.boughtAmount);
|
||||
|
||||
// Convert from one token to another.
|
||||
} else {
|
||||
@ -129,7 +131,7 @@ contract UniswapBridge is
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress);
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
state.exchange.tokenToTokenTransferInput(
|
||||
state.boughtAmount = state.exchange.tokenToTokenTransferInput(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
@ -144,6 +146,16 @@ contract UniswapBridge is
|
||||
toTokenAddress
|
||||
);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
address(this),
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
state.boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,25 @@ pragma solidity ^0.5.9;
|
||||
|
||||
contract IERC20Bridge {
|
||||
|
||||
// @dev Result of a successful bridge call.
|
||||
/// @dev Emitted when a bridge transfer is completed.
|
||||
/// @param bridge The bridge address.
|
||||
/// @param fromToken The address of the "from" token.
|
||||
/// @param toToken The address of the "to" token.
|
||||
/// @param fromTokenAmount The "from" token amount consumed.
|
||||
/// @param toTokenAmount The "to" token amount transferred.
|
||||
/// @param from Supplier of "fromToken".
|
||||
/// @param to Receiver of "toToken".
|
||||
event ERC20BridgeTransfer(
|
||||
address indexed bridge,
|
||||
address fromToken,
|
||||
address toToken,
|
||||
uint256 fromTokenAmount,
|
||||
uint256 toTokenAmount,
|
||||
address from,
|
||||
address to
|
||||
);
|
||||
|
||||
/// @dev Result of a successful bridge call.
|
||||
bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
|
||||
|
||||
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
||||
|
@ -3,7 +3,8 @@
|
||||
"version": "3.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `LibERC20Token.approveIfBelowMax()`"
|
||||
"note": "Add `LibERC20Token.approveIfBelowMax()`",
|
||||
"pr": 2512
|
||||
}
|
||||
]
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user