Skip to content

Commit 693e84c

Browse files
committed
refactor(Flashloan): encode inner call properly
1 parent fd666b5 commit 693e84c

1 file changed

Lines changed: 33 additions & 10 deletions

File tree

contracts/accessories/Flashloan.vy

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# pragma version 0.4.3
22
# pragma nonreentrancy on
3+
"""
4+
@title Purse Accessory - ERC3156 Flashloan Callback
5+
@author Purse contributors
6+
@dev
7+
This contract implements the `ERC3156FlashBorrower` interface and logic,
8+
so that the Purse can handle the flash loan context and continue operation
9+
by performing the encoded call provided with the callback data.
10+
11+
It should not be possible for anyone besides the Purse itself to call this,
12+
as that would allow aribtrary approvals to malicious addresses, as well as
13+
enable arbitrary delegate calls more generally, if it was improperly handled.
14+
"""
315
from ethereum.ercs import IERC20
416

517
interface IERC3156FlashBorrower:
@@ -21,17 +33,28 @@ def onFlashLoan(
2133
token: IERC20,
2234
amount: uint256,
2335
fee: uint256,
24-
data: Bytes[65535],
36+
data: Bytes[1 + 65535 + 32 * 2],
2537
) -> bytes32:
26-
# NOTE: Only trusted context allowed
27-
assert initiator == self, "Flashloan:!authorized"
28-
29-
# NOTE: Ensure that appropriate amount of allowance is given to caller
30-
if staticcall token.allowance(tx.origin, msg.sender) < amount + fee:
31-
extcall token.approve(msg.sender, amount + fee)
32-
33-
# NOTE: Forward whatever we specified to follow-up with back to ourselves
34-
raw_call(tx.origin, data)
38+
"""
39+
@notice Handle the ERC3156 Flashloan Callback
40+
@param initiator The initiator of the flash loan (ignored, should be `self`)
41+
@param token The token used for the flash loan
42+
@param amount The amount of `token` that is loaned
43+
@param fee The amount of `token` that must be repaid for borrowing `amount`
44+
@param data The encoded internal call to make, encoded as `to|value|data`
45+
@return The magic value `keccak256("ERC3156FlashBorrower.onFlashLoan")`
46+
"""
47+
# NOTE: Only purse is allowed to do this
48+
assert tx.origin == self, "Flashloan:!authorized"
49+
50+
# NOTE: Ensure that appropriate amount of allowance is made available to caller
51+
assert extcall token.approve(msg.sender, amount + fee, default_return_value=True)
52+
53+
# Perform encoded call as Purse
54+
to: address = empty(address)
55+
amt: uint256 = 0
56+
to, amt = abi_decode(slice(data, 0, 32*2), (address, uint256))
57+
raw_call(to, slice(data, 32*2, len(data)), value=amt)
3558

3659
# NOTE: Magic value per ERC-3156
3760
return keccak256("ERC3156FlashBorrower.onFlashLoan")

0 commit comments

Comments
 (0)