-
Notifications
You must be signed in to change notification settings - Fork 92
LF-13997 LDA 2.0 - ContractBasedNativeWrapperFacet for Celo native token #1453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mirooon
wants to merge
4
commits into
lf-13997-lda-2.0
Choose a base branch
from
lf-13997-lda-2.0-contract-based-native-wrapper
base: lf-13997-lda-2.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
script/deploy/facets/LDA/DeployContractBasedNativeWrapperFacet.s.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
| pragma solidity ^0.8.17; | ||
|
|
||
| import { ContractBasedNativeWrapperFacet } from "lifi/Periphery/LDA/Facets/ContractBasedNativeWrapperFacet.sol"; | ||
| import { DeployScriptBase } from "../utils/DeployScriptBase.sol"; | ||
|
|
||
| contract DeployScript is DeployScriptBase { | ||
| constructor() DeployScriptBase("ContractBasedNativeWrapperFacet") {} | ||
|
|
||
| function run() public returns (ContractBasedNativeWrapperFacet deployed) { | ||
| deployed = ContractBasedNativeWrapperFacet( | ||
| deploy(type(ContractBasedNativeWrapperFacet).creationCode) | ||
| ); | ||
| } | ||
| } |
13 changes: 13 additions & 0 deletions
13
script/deploy/facets/LDA/UpdateContractBasedNativeWrapperFacet.s.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
| pragma solidity ^0.8.17; | ||
|
|
||
| import { UpdateLDAScriptBase } from "./utils/UpdateLDAScriptBase.sol"; | ||
|
|
||
| contract DeployScript is UpdateLDAScriptBase { | ||
| function run() | ||
| public | ||
| returns (address[] memory facets, bytes memory cutData) | ||
| { | ||
| return update("ContractBasedNativeWrapperFacet"); | ||
| } | ||
| } |
97 changes: 97 additions & 0 deletions
97
src/Periphery/LDA/Facets/ContractBasedNativeWrapperFacet.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
| pragma solidity ^0.8.17; | ||
|
|
||
| import { LibAsset } from "lifi/Libraries/LibAsset.sol"; | ||
| import { LibPackedStream } from "lifi/Libraries/LibPackedStream.sol"; | ||
| import { InvalidCallData } from "lifi/Errors/GenericErrors.sol"; | ||
| import { BaseRouteConstants } from "../BaseRouteConstants.sol"; | ||
|
|
||
| /// @title ContractBasedNativeWrapperFacet | ||
| /// @author LI.FI (https://li.fi) | ||
| /// @notice Handles wrapping/unwrapping of dual-purpose native tokens that function as both native and ERC-20 | ||
| /// @dev Some blockchains implement native tokens with "token duality" - they function both as native currency | ||
| /// and as ERC-20 compatible tokens without requiring wrapping/unwrapping. Examples include: | ||
| /// | ||
| /// CELO Token Duality (0x471EcE3750Da237f93B8E339c536989b8978a438): | ||
| /// - Functions as both native currency (like ETH) and ERC-20 token simultaneously | ||
| /// - Native transfers work like ETH transfers on Ethereum | ||
| /// - ERC-20 transfers use standard interface but trigger native transfers via precompile | ||
| /// - balanceOf() returns native balance directly (no separate storage) | ||
| /// - No deposit()/withdraw() methods needed - transfers are always native | ||
| /// | ||
| /// This facet provides simple transfer-based operations for such tokens, | ||
| /// since they don't require actual wrapping/unwrapping operations. | ||
| /// @custom:version 1.0.0 | ||
| contract ContractBasedNativeWrapperFacet is BaseRouteConstants { | ||
| using LibPackedStream for uint256; | ||
|
|
||
| // ==== External Functions ==== | ||
|
|
||
| /// @notice Unwraps dual-purpose native token | ||
| /// @dev Dual-purpose native tokens (like CELO) don't have withdraw() methods since they're always native. | ||
| /// ERC-20 transfers automatically trigger native transfers via precompile, so we just transfer directly. | ||
| /// @param swapData Encoded swap parameters [destinationAddress] | ||
| /// @param from Token source. If from == msg.sender, pull tokens via transferFrom. | ||
| /// Otherwise, assume tokens are already held by this contract. | ||
| /// @param tokenIn Dual-purpose native token address | ||
| /// @param amountIn Amount of tokens to "unwrap" (actually just transfer natively) | ||
| function unwrapContractBasedNative( | ||
|
||
| bytes memory swapData, | ||
| address from, | ||
| address tokenIn, | ||
| uint256 amountIn | ||
| ) external payable { | ||
| address destinationAddress; | ||
| assembly { | ||
| // swapData layout: [length (32 bytes)][data...] | ||
| // We want the first 20 bytes of data, right-shifted to get address | ||
| destinationAddress := shr(96, mload(add(swapData, 32))) | ||
| } | ||
|
|
||
| if (from == msg.sender) { | ||
| LibAsset.transferFromERC20( | ||
| tokenIn, | ||
| msg.sender, | ||
| address(this), | ||
| amountIn | ||
| ); | ||
| } | ||
|
|
||
| // For dual-purpose native tokens, there's no "withdraw" - ERC-20 transfers automatically | ||
| // trigger native transfers via precompile, so we just transfer the tokens directly | ||
| if (destinationAddress != address(this)) { | ||
| LibAsset.transferERC20(tokenIn, destinationAddress, amountIn); | ||
| } | ||
| } | ||
|
|
||
| /// @notice Wraps native tokens to dual-purpose native token | ||
| /// @dev Dual-purpose native tokens (like CELO) don't have deposit() methods since they're always native. | ||
| /// ERC-20 transfers automatically trigger native transfers via precompile, so we just transfer directly. | ||
| /// @param swapData Encoded swap parameters [dualPurposeNativeToken, destinationAddress] | ||
| /// @param amountIn Amount of native tokens to "wrap" (actually just transfer natively) | ||
| function wrapContractBasedNative( | ||
|
||
| bytes memory swapData, | ||
| address, // from is not used | ||
| address, // tokenIn is not used | ||
| uint256 amountIn | ||
| ) external payable { | ||
| uint256 stream = LibPackedStream.createStream(swapData); | ||
|
|
||
| address contractBasedNativeToken = stream.readAddress(); | ||
| address destinationAddress = stream.readAddress(); | ||
|
|
||
| if (contractBasedNativeToken == address(0)) { | ||
| revert InvalidCallData(); | ||
| } | ||
|
|
||
| // For contract-based native tokens, there's no "deposit" - we just transfer the tokens directly | ||
| // since these tokens behave like native ETH but are actually ERC20 contracts | ||
| if (destinationAddress != address(this)) { | ||
| LibAsset.transferERC20( | ||
| contractBasedNativeToken, | ||
| destinationAddress, | ||
| amountIn | ||
| ); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.