@@ -11,24 +11,18 @@ import "../../lib/MathUint.sol";
1111import "../../lib/ReentrancyGuard.sol " ;
1212import "../../lib/SignatureUtil.sol " ;
1313
14-
15- /// @title Fast withdrawal agent implementation. The fast withdrawal request reduces to
16- /// a normal onchain withdrawal request after a specified time limit has exceeded.
14+ /// @title Fast withdrawal agent implementation. With the help of liquidity providers (LPs),
15+ /// exchange operators can convert any normal withdrawals into fast withdrawals.
1716///
1817/// Fast withdrawals are a way for the owner to provide instant withdrawals for
1918/// users with the help of a liquidity provider and conditional transfers.
2019///
2120/// A fast withdrawal requires the non-trustless cooperation of 2 parties:
2221/// - A liquidity provider which provides funds to users immediately onchain
2322/// - The operator which will make sure the user has sufficient funds offchain
24- /// so that the liquidity provider can be paid back offchain using a conditional transfer.
25- /// The operator also needs to process those conditional transfers so that the
26- /// liquidity provider receives its funds back in its own account where it
27- /// again has full custody over it.
28- ///
29- /// However, there is a special case when the fast withdrawal reduces to a standard
30- /// withdrawal and the fee is paid onchain. In this case the withdrawal can be
31- /// done completely trustless, no cooperation with the owner is needed.
23+ /// so that the liquidity provider can be paid back.
24+ /// The operator also needs to process those withdrawals so that the
25+ /// liquidity provider receives its funds back.
3226///
3327/// We require the fast withdrawals to be executed by the liquidity provider (as msg.sender)
3428/// so that the liquidity provider can impose its own rules on how its funds are spent. This will
@@ -44,49 +38,44 @@ import "../../lib/SignatureUtil.sol";
4438/// authorize this contract as their agent.
4539///
4640/// @author Brecht Devos - <[email protected] > 41+ /// @author Kongliang Zhong - <[email protected] > 42+ /// @author Daniel Wang - <[email protected] > 4743contract FastWithdrawalAgent is ReentrancyGuard
4844{
4945 using AddressUtil for address ;
5046 using AddressUtil for address payable ;
5147 using ERC20SafeTransfer for address ;
5248 using MathUint for uint ;
53- using SignatureUtil for bytes32 ;
5449
55- struct FastWithdrawal
50+ event Processed (
51+ address exchange ,
52+ address from ,
53+ address to ,
54+ address token ,
55+ uint96 amount ,
56+ address provider ,
57+ bool success
58+ );
59+
60+ struct Withdrawal
5661 {
5762 address exchange;
5863 address from; // The owner of the account
59- address to; // The address that will receive the tokens withdrawn
64+ address to; // The `to` address of the withdrawal
6065 address token;
6166 uint96 amount;
62- address feeToken;
63- uint96 fee;
64- uint32 nonce;
65- uint32 validUntil;
66-
67- bytes signature;
68- }
69-
70- // EIP712
71- bytes32 constant public FASTWITHDRAWAL_TYPEHASH = keccak256 (
72- "FastWithdrawal(address exchange,address from,address to,address token,uint96 amount,address feeToken,uint96 fee,uint32 nonce,uint32 validUntil) "
73- );
74- bytes32 public DOMAIN_SEPARATOR;
75-
76- constructor ()
77- {
78- DOMAIN_SEPARATOR = EIP712.hash (EIP712.Domain ("FastWithdrawalAgent " , "1.0 " , address (this )));
67+ uint32 storageID;
7968 }
8069
8170 // This method needs to be called by any liquidity provider
82- function executeFastWithdrawals (FastWithdrawal [] memory fastWithdrawals )
71+ function executeFastWithdrawals (Withdrawal [] calldata withdrawals )
8372 public
8473 nonReentrant
8574 payable
8675 {
8776 // Do all fast withdrawals
88- for (uint i = 0 ; i < fastWithdrawals .length ; i++ ) {
89- executeFastWithdrawal (fastWithdrawals [i]);
77+ for (uint i = 0 ; i < withdrawals .length ; i++ ) {
78+ executeInternal (withdrawals [i]);
9079 }
9180 // Return any ETH left into this contract
9281 // (can happen when more ETH is sent than needed for the fast withdrawals)
@@ -95,68 +84,51 @@ contract FastWithdrawalAgent is ReentrancyGuard
9584
9685 // -- Internal --
9786
98- function executeFastWithdrawal (FastWithdrawal memory fastWithdrawal )
87+ function executeInternal (Withdrawal calldata withdrawal )
9988 internal
10089 {
90+ require (
91+ withdrawal.exchange != address (0 ) &&
92+ withdrawal.from != address (0 ) &&
93+ withdrawal.to != address (0 ) &&
94+ withdrawal.amount != 0 ,
95+ "INVALID_WITHDRAWAL "
96+ );
97+
10198 // The liquidity provider always authorizes the fast withdrawal by being the direct caller
10299 address payable liquidityProvider = msg .sender ;
103100
104- if (fastWithdrawal.signature.length > 0 ) {
105- // Compute the hash
106- bytes32 hash = EIP712.hashPacked (
107- DOMAIN_SEPARATOR,
108- keccak256 (
109- abi.encodePacked (
110- FASTWITHDRAWAL_TYPEHASH,
111- fastWithdrawal.exchange,
112- fastWithdrawal.from,
113- fastWithdrawal.to,
114- fastWithdrawal.token,
115- fastWithdrawal.amount,
116- fastWithdrawal.feeToken,
117- fastWithdrawal.fee,
118- fastWithdrawal.nonce,
119- fastWithdrawal.validUntil
120- )
121- )
122- );
123-
124- // Check the signature
125- require (hash.verifySignature (fastWithdrawal.from, fastWithdrawal.signature), "INVALID_SIGNATURE " );
126-
127- // Check the time limit
128- require (block .timestamp <= fastWithdrawal.validUntil, "TX_EXPIRED " );
129-
130- // Approve the offchain transfer from the account that's withdrawing back to the liquidity provider
131- IExchangeV3 (fastWithdrawal.exchange).approveOffchainTransfer (
132- fastWithdrawal.from,
101+ bool success;
102+ // Override the destination address of a withdrawal to the address of the liquidity provider
103+ try IExchangeV3 (withdrawal.exchange).setWithdrawalRecipient (
104+ withdrawal.from,
105+ withdrawal.to,
106+ withdrawal.token,
107+ withdrawal.amount,
108+ withdrawal.storageID,
109+ liquidityProvider
110+ ) {
111+ // Transfer the tokens immediately to the requested address
112+ // using funds from the liquidity provider (`msg.sender`).
113+ transfer (
133114 liquidityProvider,
134- fastWithdrawal.token,
135- fastWithdrawal.amount,
136- fastWithdrawal.feeToken,
137- fastWithdrawal.fee,
138- fastWithdrawal.validUntil,
139- fastWithdrawal.nonce
140- );
141- } else {
142- // Override the destination address of a withdrawal to the address of the liquidity provider
143- IExchangeV3 (fastWithdrawal.exchange).setWithdrawalRecipient (
144- fastWithdrawal.from,
145- fastWithdrawal.to,
146- fastWithdrawal.token,
147- fastWithdrawal.amount,
148- fastWithdrawal.nonce,
149- liquidityProvider
115+ withdrawal.to,
116+ withdrawal.token,
117+ withdrawal.amount
150118 );
119+ success = true ;
120+ } catch {
121+ success = false ;
151122 }
152123
153- // Transfer the tokens immediately to the requested address
154- // using funds from the liquidity provider (`msg.sender`).
155- transfer (
124+ emit Processed (
125+ withdrawal.exchange,
126+ withdrawal.from,
127+ withdrawal.to,
128+ withdrawal.token,
129+ withdrawal.amount,
156130 liquidityProvider,
157- fastWithdrawal.to,
158- fastWithdrawal.token,
159- fastWithdrawal.amount
131+ success
160132 );
161133 }
162134
0 commit comments