-
Notifications
You must be signed in to change notification settings - Fork 465
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So excited for this!
using LibSafeMath for uint256; | ||
|
||
// @dev Result of a successful bridge call. | ||
bytes4 constant public BRIDGE_SUCCESS = 0xb5d40d78; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How was this derived?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crypto.randomBytes(4)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably better to add some meaning to them. Maybe just reuse the PROXY_ID
?
/// @param to Address to transfer asset to. | ||
/// @param amount Amount of asset to transfer. | ||
/// @return success The magic bytes `0xb5d40d78` if successful. | ||
function transfer( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nits about the signature of this function:
transferFrom
is more descriptive than transfer
. It's somewhat awkward that this would be the 3rd different transferFrom
used in the proxies, so maybe there is a better name... but I don't love transfer
.
I also think bridgeData
should be the last parameter. It is optional and probably won't be used in all bridge contracts. Making it the last parameter is consistent with all of the token standards that have a similar parameter in their own transfer functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to avoid transferFrom
because it makes it really hard to explain this pattern to people (transferFrom
calls transferFrom
calls transferFrom
). Maybe convertFrom
? exchangeFrom
? bridgeFrom
? swapFrom
? settleFrom
? I'm at a loss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
withdrawTo
perhaps?
require(success == BRIDGE_SUCCESS, "BRIDGE_FAILED"); | ||
// Ensure that the balance of `to` has increased by at least `amount`. | ||
require( | ||
balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I feel like balanceOf(tokenAddress, to) >= balanceBefore.safeAdd(amount)
is slightly more intuitive. Not a huge deal either way.
view | ||
returns (uint256 balance) | ||
{ | ||
(address tokenAddress, ,) = abi.decode( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be made more efficient with:
(address tokenAddress) = abi.decode(
assetData.sliceDestructive(4, assetData.length),
(address)
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was trying to sneak in some extra asset data validation this way, but I guess since it's not checking the selector, it's not even doing that very well.
// @dev Result of a successful bridge call. | ||
bytes4 constant public BRIDGE_SUCCESS = 0xb5d40d78; | ||
// @dev Id of this proxy. | ||
// bytes4(keccak256("ERC20BridgeProxy(address,address,bytes)")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably use ERC20Bridge
rather than ERC20BridgeProxy
to be consistent with the other ids. We should also add an entry for this to IAssetData
.
…C20Bridge.withdrawTo()`. `@0x/contracts-asset-proxy`: Make `bridgeData` last parameter in `IERC20Bridge.withdrawTo()`. `@0x/contracts-asset-proxy`: Reuse `PROXY_ID` as `BRIDGE_SUCCESS`.
…to `IAssetData`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great! I just had a few nits on tests, and then this looks good to go
} from '../src'; | ||
|
||
blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||
const PROXY_ID = '0xdc1600f3'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should add this to AssetProxyId
in packages/types/
return (logs as any) as DecodedLogs; | ||
} | ||
|
||
it('succeeds if the bridge succeeds and balance increases', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
it('succeeds if the bridge succeeds and balance increases', async () => { | |
it('succeeds if the bridge succeeds and balance increases by `amount`', async () => { |
return expect(tx).to.revertWith(revertError); | ||
}); | ||
|
||
it('fails if balance of `to` increases by `amount - 1`', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
it('fails if balance of `to` increases by `amount - 1`', async () => { | |
it('fails if balance of `to` increases by less than `amount`', async () => { |
For consistency with the above tests.
return expect(tx).to.revertWith('BRIDGE_UNDERPAY'); | ||
}); | ||
|
||
it('fails if balance of `to` decreases', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙏
return expect(tx).to.revertWith('BRIDGE_FAILED'); | ||
}); | ||
|
||
it('fails if bridge is an EOA', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great +1! Please hit http://merge.it (~‾▿‾)~
Description
Say hello to the new
ERC20BridgeProxy
!Overview
The
ERC20BridgeProxy
essentially does just two things:withdrawTo()
on an instance of theIERC20Bridge
contract.to
has increased byamount
after the call.It is up to the
IERC20Bridge
contract to actually perform the transfer. If the bridge contract needs the taker funds in order to complete the transfer (like for Eth2Dai/Uniswap bridges), the order should be constructed withmaker = IERC20Bridge
.AssetData
IERC20Bridge
A valid bridge contract only has to export one function:
Testing instructions
Types of changes
Checklist:
[WIP]
if necessary.Addresses 0xProject/ZEIPs/issues/47