Skip to content

Commit 09f8ca0

Browse files
committed
feat: add bridger
1 parent 027cd1c commit 09f8ca0

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed

contracts/bridgers/IBridger.vyi

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# pragma version ~=0.4.0
2+
"""
3+
@title Curve Bridge Adapter
4+
@license MIT
5+
@author CurveFi
6+
@notice Interface mainly used for bridging Curve emissions to L2s and collected fees to Ethereum.
7+
"""
8+
9+
from ethereum.ercs import IERC20
10+
11+
12+
@external
13+
@payable
14+
def bridge(_token: IERC20, _to: address, _amount: uint256, _min_amount: uint256=0) -> uint256:
15+
"""
16+
@notice Bridge `_token`
17+
@param _token The ERC20 asset to bridge
18+
@param _to The receiver on `_chain_id`
19+
@param _amount The amount of `_token` to deposit, 2^256-1 for the whole balance
20+
@param _min_amount Minimum amount when to bridge
21+
@return Bridged amount
22+
"""
23+
...
24+
25+
26+
@view
27+
@external
28+
def check(_account: address) -> bool:
29+
"""
30+
@notice Check if `_account` may bridge via `transmit_emissions`
31+
@param _account The account to check
32+
"""
33+
...
34+
35+
36+
@view
37+
@external
38+
def cost() -> uint256:
39+
"""
40+
@notice Cost in ETH to bridge, not all chains are supported
41+
"""
42+
...

contracts/bridgers/LzXdaoBridger.vy

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# @version 0.4.0
2+
"""
3+
@title LzXdaoBridger
4+
@custom:version 0.0.1
5+
@author Curve.Fi
6+
@license Copyright (c) Curve.Fi, 2020-2024 - all rights reserved
7+
@notice Curve Xdao Layer Zero bridge wrapper
8+
"""
9+
10+
version: public(constant(String[8])) = "0.0.1"
11+
12+
from ethereum.ercs import IERC20
13+
import IBridger
14+
15+
implements: IBridger
16+
17+
18+
interface Bridge:
19+
def bridge(_receiver: address, _amount: uint256, _refund: address): payable
20+
def quote() -> uint256: view
21+
22+
23+
CRV20: constant(address) = 0xD533a949740bb3306d119CC777fa900bA034cd52
24+
BRIDGE: public(immutable(Bridge))
25+
26+
DESTINATION_CHAIN_ID: public(immutable(uint256))
27+
28+
29+
@deploy
30+
def __init__(_bridge: Bridge, _chain_id: uint256):
31+
"""
32+
@param _bridge Layer Zero Bridge of CRV
33+
@param _chain_id Chain ID to bridge to (actual, not LZ)
34+
"""
35+
BRIDGE = _bridge
36+
DESTINATION_CHAIN_ID = _chain_id
37+
38+
assert extcall IERC20(CRV20).approve(BRIDGE.address, max_value(uint256))
39+
40+
41+
@external
42+
@payable
43+
def bridge(_token: IERC20, _to: address, _amount: uint256, _min_amount: uint256=0) -> uint256:
44+
"""
45+
@notice Bridge `_token` through XDAO Layer Zero
46+
@param _token The ERC20 asset to bridge
47+
@param _to The receiver on `_chain_id`
48+
@param _amount The amount of `_token` to deposit, 2^256-1 for the whole balance
49+
@param _min_amount Minimum amount when to bridge
50+
@return Bridged amount
51+
"""
52+
amount: uint256 = _amount
53+
if amount == max_value(uint256):
54+
amount = min(staticcall _token.balanceOf(msg.sender), staticcall _token.allowance(msg.sender, self))
55+
assert amount >= _min_amount, "Amount too small"
56+
57+
assert extcall _token.transferFrom(msg.sender, self, amount)
58+
59+
extcall BRIDGE.bridge(_to, amount, msg.sender, value=self.balance)
60+
return amount
61+
62+
63+
@view
64+
@external
65+
def cost() -> uint256:
66+
"""
67+
@notice Cost in ETH to bridge
68+
"""
69+
return staticcall BRIDGE.quote()
70+
71+
72+
@view
73+
@external
74+
def check(_account: address) -> bool:
75+
"""
76+
@notice Check if `_account` is allowed to bridge
77+
@param _account The account to check
78+
"""
79+
return True

tests/forked/test_bridgers.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,21 @@ def test_polygonzkevm_bridger(alice, crv_token, PolygonzkEVMBridger):
159159
assert crv_token.balanceOf(bridge) == balance_before + 10**18
160160
assert "BridgeEvent" in tx.events
161161
assert tx.events["BridgeEvent"].values()[2:5] == [crv_token, 3, bridger]
162+
163+
164+
@pytest.skip(msg="vyper 0.4.0 not supported yet")
165+
def test_lz_xdao_bridger(alice, bob, crv_token, LzXdaoBridger):
166+
bridge = "0xC91113B4Dd89dd20FDEECDAC82477Bc99A840355"
167+
bridger = LzXdaoBridger.deploy(bridge, 56, {"from": alice})
168+
169+
assert bridger.check(alice) is True
170+
171+
crv_token.approve(bridger, 2 ** 256 - 1, {"from": alice})
172+
173+
balance_before = crv_token.balanceOf(alice)
174+
tx = bridger.bridge(crv_token, bob, 10 ** 18, {"from": alice, "value": bridger.cost()})
175+
176+
assert crv_token.balanceOf(alice) == balance_before - 10 ** 18
177+
assert crv_token.balanceOf(bridger) == 0
178+
assert "BridgeSent" in tx.events
179+
assert tx.events["BridgeSent"].values() == [bob, 10 ** 18]

0 commit comments

Comments
 (0)