-
Notifications
You must be signed in to change notification settings - Fork 47
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
Swap: add Solana interact task #192
Conversation
WalkthroughWalkthroughThe changes across the Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 4
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (2)
omnichain/swap/package-lock.json
is excluded by!**/package-lock.json
omnichain/swap/yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
Files selected for processing (15)
- omnichain/swap/.gitignore (1 hunks)
- omnichain/swap/README.md (1 hunks)
- omnichain/swap/contracts/Swap.sol (1 hunks)
- omnichain/swap/contracts/SwapToAnyToken.sol (4 hunks)
- omnichain/swap/contracts/shared/TestUniswapCore.sol (1 hunks)
- omnichain/swap/contracts/shared/TestUniswapRouter.sol (1 hunks)
- omnichain/swap/foundry.toml (1 hunks)
- omnichain/swap/hardhat.config.ts (2 hunks)
- omnichain/swap/package.json (4 hunks)
- omnichain/swap/tasks/interact.ts (1 hunks)
- omnichain/swap/tasks/solana/deposit.ts (1 hunks)
- omnichain/swap/tasks/solana/gateway.json (1 hunks)
- omnichain/swap/tasks/solana/interact.ts (1 hunks)
- omnichain/swap/test/SwapToAnyToken.spec.ts (1 hunks)
- omnichain/swap/tsconfig.json (1 hunks)
Files skipped from review due to trivial changes (6)
- omnichain/swap/.gitignore
- omnichain/swap/contracts/shared/TestUniswapCore.sol
- omnichain/swap/contracts/shared/TestUniswapRouter.sol
- omnichain/swap/foundry.toml
- omnichain/swap/tasks/interact.ts
- omnichain/swap/test/SwapToAnyToken.spec.ts
Additional context used
Markdownlint
omnichain/swap/README.md
7-7: null
Fenced code blocks should have a language specified(MD040, fenced-code-language)
Additional comments not posted (22)
omnichain/swap/tsconfig.json (2)
3-3
: LGTM!Changing the
module
option to"nodenext"
aligns the project with the latest Node.js module handling practices, allowing for better interoperability with ES modules.
4-4
: LGTM!Adding the
moduleResolution
option with the value"nodenext"
ensures consistent module resolution in line with the latest Node.js practices.omnichain/swap/README.md (2)
5-7
: LGTM!The addition of installation instructions is clear and concise, providing essential information for getting started.
Tools
Markdownlint
7-7: null
Fenced code blocks should have a language specified(MD040, fenced-code-language)
13-15
: LGTM!The new section effectively guides users to further learning resources, enhancing the onboarding experience.
omnichain/swap/hardhat.config.ts (2)
2-2
: LGTM!The addition of the import for Solana interaction expands the project's functionality to support interactions with the Solana blockchain.
3-3
: LGTM!The addition of the import for local network tasks enhances the project's capabilities by supporting local network tasks.
omnichain/swap/tasks/solana/interact.ts (1)
1-6
: LGTM!The import statements are necessary and correctly included.
omnichain/swap/tasks/solana/deposit.ts (1)
1-6
: LGTM!The import statements are necessary and correctly included.
omnichain/swap/package.json (6)
9-9
: LGTM!The addition of the "lint" script is a good practice to ensure code quality.
10-10
: LGTM!The addition of the "deploy" script enhances the project's deployment capabilities.
19-19
: LGTM!The addition of the
@nomicfoundation/hardhat-foundry
dependency indicates an integration with the Foundry framework, which can be beneficial for the project.
31-31
: LGTM!The replacement of the
@zetachain/toolkit
dependency with@zetachain/localnet
suggests a shift in the toolkit being utilized for ZetaChain-related functionalities.
32-32
: LGTM!The addition of the
@zetachain/protocol-contracts
dependency indicates the use of protocol contracts for ZetaChain-related functionalities.
47-47
: LGTM!The update of the
hardhat
dependency version may include important bug fixes or new features relevant to the development environment.omnichain/swap/contracts/SwapToAnyToken.sol (7)
Line range hint
1-1
: LGTM!The removal of the
TransferFailed
error declaration simplifies error handling within the contract.
Line range hint
1-1
: LGTM!The removal of the
receive()
function indicates a shift in the contract's handling of incoming funds.
40-48
: LGTM!The refactoring of the
onCrossChainCall
function consolidates the handling of theparams
structure and simplifies the decoding of themessage
variable.
Line range hint
58-80
: LGTM!The update to the
swapAndWithdraw
function reduces the function signature's complexity and enhances the maintainability of the code.
Line range hint
1-1
: LGTM!The removal of the
swap
function indicates a potential shift in how the contract handles token swaps.
78-82
: LGTM!The update to the withdrawal process streamlines the code and ensures consistency in how withdrawal actions are processed.
Line range hint
1-1
: LGTM!The removal of checks for the
wZetaContractAddress
and associated Ether withdrawal logic indicates a potential shift in how the contract interacts with wrapped tokens.omnichain/swap/tasks/solana/gateway.json (1)
1-497
: LGTM! But verify the consistency of the definitions with the program's logic.The file appears to be well-structured and follows the conventions for Solana programs. However, ensure that the instructions, accounts, and errors are correctly defined and consistent with the program's logic.
task("interact-solana", "", main) | ||
.addParam("amount", "Amount of SOL to deposit") | ||
.addParam("contract", "Universal contract address") | ||
.addParam("targetToken") | ||
.addParam("recipient") | ||
.addOptionalParam("withdraw") | ||
.addOptionalParam("api", "Solana API", "https://api.devnet.solana.com") | ||
.addOptionalParam("idPath", "Path to id.json", "~/.config/solana/id.json"); |
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.
Enhance parameter validation.
The task registration is correctly implemented but could benefit from additional parameter validation.
Add validation for the recipient
parameter.
Apply this diff to enhance the task registration:
task("interact-solana", "", main)
.addParam("amount", "Amount of SOL to deposit")
.addParam("contract", "Universal contract address")
.addParam("targetToken")
.addParam("recipient", "Recipient address")
.addOptionalParam("withdraw")
.addOptionalParam("api", "Solana API", "https://api.devnet.solana.com")
.addOptionalParam("idPath", "Path to id.json", "~/.config/solana/id.json")
.addAction(async (args, hre) => {
if (!args.recipient || args.recipient.length === 0) {
throw new Error("Invalid recipient address");
}
});
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
task("interact-solana", "", main) | |
.addParam("amount", "Amount of SOL to deposit") | |
.addParam("contract", "Universal contract address") | |
.addParam("targetToken") | |
.addParam("recipient") | |
.addOptionalParam("withdraw") | |
.addOptionalParam("api", "Solana API", "https://api.devnet.solana.com") | |
.addOptionalParam("idPath", "Path to id.json", "~/.config/solana/id.json"); | |
task("interact-solana", "", main) | |
.addParam("amount", "Amount of SOL to deposit") | |
.addParam("contract", "Universal contract address") | |
.addParam("targetToken") | |
.addParam("recipient", "Recipient address") | |
.addOptionalParam("withdraw") | |
.addOptionalParam("api", "Solana API", "https://api.devnet.solana.com") | |
.addOptionalParam("idPath", "Path to id.json", "~/.config/solana/id.json") | |
.addAction(async (args, hre) => { | |
if (!args.recipient || args.recipient.length === 0) { | |
throw new Error("Invalid recipient address"); | |
} | |
}); |
const main = async (args: any, hre: HardhatRuntimeEnvironment) => { | ||
let recipient; | ||
try { | ||
if (bech32.decode(args.recipient)) { | ||
recipient = utils.solidityPack( | ||
["bytes"], | ||
[utils.toUtf8Bytes(args.recipient)] | ||
); | ||
} | ||
} catch (e) { | ||
recipient = args.recipient; | ||
} | ||
const { amount, contract, targetToken, withdraw, api, idPath } = args; | ||
const params = [ | ||
["address", "bytes", "bool"], | ||
[targetToken, recipient, withdraw], | ||
]; | ||
await deposit({ amount, api, contract, idPath, params }); | ||
}; |
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.
Enhance input validation and error handling.
The main
function is correctly implemented but could benefit from additional input validation and error handling.
- Add input validation for
amount
,contract
, andtargetToken
. - Improve error handling for the
bech32.decode
call.
Apply this diff to enhance the function:
const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
let recipient;
// Validate inputs
if (!args.amount || isNaN(args.amount) || args.amount <= 0) {
throw new Error("Invalid amount");
}
if (!args.contract || !utils.isAddress(args.contract)) {
throw new Error("Invalid contract address");
}
if (!args.targetToken || !utils.isAddress(args.targetToken)) {
throw new Error("Invalid target token address");
}
try {
if (bech32.decode(args.recipient)) {
recipient = utils.solidityPack(
["bytes"],
[utils.toUtf8Bytes(args.recipient)]
);
}
} catch (e) {
recipient = args.recipient;
}
const { amount, contract, targetToken, withdraw, api, idPath } = args;
const params = [
["address", "bytes", "bool"],
[targetToken, recipient, withdraw],
];
await deposit({ amount, api, contract, idPath, params });
};
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const main = async (args: any, hre: HardhatRuntimeEnvironment) => { | |
let recipient; | |
try { | |
if (bech32.decode(args.recipient)) { | |
recipient = utils.solidityPack( | |
["bytes"], | |
[utils.toUtf8Bytes(args.recipient)] | |
); | |
} | |
} catch (e) { | |
recipient = args.recipient; | |
} | |
const { amount, contract, targetToken, withdraw, api, idPath } = args; | |
const params = [ | |
["address", "bytes", "bool"], | |
[targetToken, recipient, withdraw], | |
]; | |
await deposit({ amount, api, contract, idPath, params }); | |
}; | |
const main = async (args: any, hre: HardhatRuntimeEnvironment) => { | |
let recipient; | |
// Validate inputs | |
if (!args.amount || isNaN(args.amount) || args.amount <= 0) { | |
throw new Error("Invalid amount"); | |
} | |
if (!args.contract || !utils.isAddress(args.contract)) { | |
throw new Error("Invalid contract address"); | |
} | |
if (!args.targetToken || !utils.isAddress(args.targetToken)) { | |
throw new Error("Invalid target token address"); | |
} | |
try { | |
if (bech32.decode(args.recipient)) { | |
recipient = utils.solidityPack( | |
["bytes"], | |
[utils.toUtf8Bytes(args.recipient)] | |
); | |
} | |
} catch (e) { | |
recipient = args.recipient; | |
} | |
const { amount, contract, targetToken, withdraw, api, idPath } = args; | |
const params = [ | |
["address", "bytes", "bool"], | |
[targetToken, recipient, withdraw], | |
]; | |
await deposit({ amount, api, contract, idPath, params }); | |
}; |
export const deposit = async (args: { | ||
amount: number; | ||
api: string; | ||
contract: string; | ||
idPath: string; | ||
params: any[]; | ||
}) => { | ||
const keypair = await getKeypairFromFile(args.idPath); | ||
const wallet = new anchor.Wallet(keypair); | ||
|
||
const connection = new anchor.web3.Connection(args.api); | ||
const provider = new anchor.AnchorProvider( | ||
connection, | ||
wallet, | ||
anchor.AnchorProvider.defaultOptions() | ||
); | ||
anchor.setProvider(provider); | ||
|
||
const programId = new web3.PublicKey(Gateway_IDL.address); | ||
const gatewayProgram = new Program(Gateway_IDL as anchor.Idl, provider); | ||
|
||
const seeds = [Buffer.from(SEED, "utf-8")]; | ||
const [pdaAccount] = web3.PublicKey.findProgramAddressSync(seeds, programId); | ||
|
||
const depositAmount = new BN(web3.LAMPORTS_PER_SOL * args.amount); | ||
|
||
try { | ||
const tx = new web3.Transaction(); | ||
const m = Buffer.from( | ||
ethers.utils.arrayify( | ||
args.contract + | ||
ethers.utils.defaultAbiCoder | ||
.encode(args.params[0], args.params[1]) | ||
.slice(2) | ||
) | ||
); | ||
const depositInstruction = await gatewayProgram.methods | ||
.deposit(depositAmount, m) | ||
.accounts({ | ||
pda: pdaAccount, | ||
signer: wallet.publicKey, | ||
systemProgram: web3.SystemProgram.programId, | ||
}) | ||
.instruction(); | ||
|
||
tx.add(depositInstruction); | ||
|
||
// Send the transaction | ||
const txSignature = await web3.sendAndConfirmTransaction(connection, tx, [ | ||
keypair, | ||
]); | ||
|
||
console.log("Transaction signature:", txSignature); | ||
} catch (error) { | ||
console.error("Transaction failed:", error); | ||
} |
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.
Enhance input validation and error handling.
The deposit
function is correctly implemented but could benefit from additional input validation and error handling.
- Add input validation for
amount
,contract
, andapi
. - Improve error handling for the transaction execution.
Apply this diff to enhance the function:
export const deposit = async (args: {
amount: number;
api: string;
contract: string;
idPath: string;
params: any[];
}) => {
// Validate inputs
if (!args.amount || isNaN(args.amount) || args.amount <= 0) {
throw new Error("Invalid amount");
}
if (!args.contract || !ethers.utils.isAddress(args.contract)) {
throw new Error("Invalid contract address");
}
if (!args.api || !args.api.startsWith("http")) {
throw new Error("Invalid API URL");
}
const keypair = await getKeypairFromFile(args.idPath);
const wallet = new anchor.Wallet(keypair);
const connection = new anchor.web3.Connection(args.api);
const provider = new anchor.AnchorProvider(
connection,
wallet,
anchor.AnchorProvider.defaultOptions()
);
anchor.setProvider(provider);
const programId = new web3.PublicKey(Gateway_IDL.address);
const gatewayProgram = new Program(Gateway_IDL as anchor.Idl, provider);
const seeds = [Buffer.from(SEED, "utf-8")];
const [pdaAccount] = web3.PublicKey.findProgramAddressSync(seeds, programId);
const depositAmount = new BN(web3.LAMPORTS_PER_SOL * args.amount);
try {
const tx = new web3.Transaction();
const m = Buffer.from(
ethers.utils.arrayify(
args.contract +
ethers.utils.defaultAbiCoder
.encode(args.params[0], args.params[1])
.slice(2)
)
);
const depositInstruction = await gatewayProgram.methods
.deposit(depositAmount, m)
.accounts({
pda: pdaAccount,
signer: wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.instruction();
tx.add(depositInstruction);
// Send the transaction
const txSignature = await web3.sendAndConfirmTransaction(connection, tx, [
keypair,
]);
console.log("Transaction signature:", txSignature);
} catch (error) {
console.error("Transaction failed:", error);
}
};
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const deposit = async (args: { | |
amount: number; | |
api: string; | |
contract: string; | |
idPath: string; | |
params: any[]; | |
}) => { | |
const keypair = await getKeypairFromFile(args.idPath); | |
const wallet = new anchor.Wallet(keypair); | |
const connection = new anchor.web3.Connection(args.api); | |
const provider = new anchor.AnchorProvider( | |
connection, | |
wallet, | |
anchor.AnchorProvider.defaultOptions() | |
); | |
anchor.setProvider(provider); | |
const programId = new web3.PublicKey(Gateway_IDL.address); | |
const gatewayProgram = new Program(Gateway_IDL as anchor.Idl, provider); | |
const seeds = [Buffer.from(SEED, "utf-8")]; | |
const [pdaAccount] = web3.PublicKey.findProgramAddressSync(seeds, programId); | |
const depositAmount = new BN(web3.LAMPORTS_PER_SOL * args.amount); | |
try { | |
const tx = new web3.Transaction(); | |
const m = Buffer.from( | |
ethers.utils.arrayify( | |
args.contract + | |
ethers.utils.defaultAbiCoder | |
.encode(args.params[0], args.params[1]) | |
.slice(2) | |
) | |
); | |
const depositInstruction = await gatewayProgram.methods | |
.deposit(depositAmount, m) | |
.accounts({ | |
pda: pdaAccount, | |
signer: wallet.publicKey, | |
systemProgram: web3.SystemProgram.programId, | |
}) | |
.instruction(); | |
tx.add(depositInstruction); | |
// Send the transaction | |
const txSignature = await web3.sendAndConfirmTransaction(connection, tx, [ | |
keypair, | |
]); | |
console.log("Transaction signature:", txSignature); | |
} catch (error) { | |
console.error("Transaction failed:", error); | |
} | |
export const deposit = async (args: { | |
amount: number; | |
api: string; | |
contract: string; | |
idPath: string; | |
params: any[]; | |
}) => { | |
// Validate inputs | |
if (!args.amount || isNaN(args.amount) || args.amount <= 0) { | |
throw new Error("Invalid amount"); | |
} | |
if (!args.contract || !ethers.utils.isAddress(args.contract)) { | |
throw new Error("Invalid contract address"); | |
} | |
if (!args.api || !args.api.startsWith("http")) { | |
throw new Error("Invalid API URL"); | |
} | |
const keypair = await getKeypairFromFile(args.idPath); | |
const wallet = new anchor.Wallet(keypair); | |
const connection = new anchor.web3.Connection(args.api); | |
const provider = new anchor.AnchorProvider( | |
connection, | |
wallet, | |
anchor.AnchorProvider.defaultOptions() | |
); | |
anchor.setProvider(provider); | |
const programId = new web3.PublicKey(Gateway_IDL.address); | |
const gatewayProgram = new Program(Gateway_IDL as anchor.Idl, provider); | |
const seeds = [Buffer.from(SEED, "utf-8")]; | |
const [pdaAccount] = web3.PublicKey.findProgramAddressSync(seeds, programId); | |
const depositAmount = new BN(web3.LAMPORTS_PER_SOL * args.amount); | |
try { | |
const tx = new web3.Transaction(); | |
const m = Buffer.from( | |
ethers.utils.arrayify( | |
args.contract + | |
ethers.utils.defaultAbiCoder | |
.encode(args.params[0], args.params[1]) | |
.slice(2) | |
) | |
); | |
const depositInstruction = await gatewayProgram.methods | |
.deposit(depositAmount, m) | |
.accounts({ | |
pda: pdaAccount, | |
signer: wallet.publicKey, | |
systemProgram: web3.SystemProgram.programId, | |
}) | |
.instruction(); | |
tx.add(depositInstruction); | |
// Send the transaction | |
const txSignature = await web3.sendAndConfirmTransaction(connection, tx, [ | |
keypair, | |
]); | |
console.log("Transaction signature:", txSignature); | |
} catch (error) { | |
console.error("Transaction failed:", error); | |
} | |
}; |
(gasZRC20, gasFee) = IZRC20(params.target).withdrawGasFee(); | ||
|
||
inputForGas = SwapHelperLib.swapTokensForExactTokens( | ||
systemContract, | ||
inputToken, | ||
zrc20, | ||
gasFee, | ||
gasZRC20, | ||
amount | ||
); | ||
|
||
uint256 outputAmount = SwapHelperLib.swapExactTokensForTokens( | ||
systemContract, | ||
inputToken, | ||
zrc20, | ||
amount - inputForGas, | ||
targetToken, | ||
params.target, | ||
0 | ||
); | ||
|
||
IZRC20(gasZRC20).approve(targetToken, gasFee); | ||
IZRC20(targetToken).withdraw(recipient, outputAmount); | ||
IZRC20(gasZRC20).approve(params.target, gasFee); | ||
IZRC20(params.target).withdraw(params.to, outputAmount); |
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.
Add comments explaining the new params
structure.
The changes improve the clarity and consistency of the function but could benefit from additional comments explaining the new params
structure.
Add comments to explain the new params
structure.
Apply this diff to enhance the function:
function onCrossChainCall(
zContext calldata context,
address zrc20,
uint256 amount,
bytes calldata message
) external virtual override onlySystem(systemContract) {
Params memory params = Params({target: address(0), to: bytes("")});
if (context.chainID == BITCOIN) {
params.target = BytesHelperLib.bytesToAddress(message, 0);
params.to = abi.encodePacked(
BytesHelperLib.bytesToAddress(message, 20)
);
} else {
(address targetToken, bytes memory recipient) = abi.decode(
message,
(address, bytes)
);
params.target = targetToken;
params.to = recipient;
}
uint256 inputForGas;
address gasZRC20;
uint256 gasFee;
// Retrieve the gas fee for the target token
(gasZRC20, gasFee) = IZRC20(params.target).withdrawGasFee();
// Swap tokens for the exact amount of gas fee
inputForGas = SwapHelperLib.swapTokensForExactTokens(
systemContract,
zrc20,
gasFee,
gasZRC20,
amount
);
// Swap the remaining tokens for the target token
uint256 outputAmount = SwapHelperLib.swapExactTokensForTokens(
systemContract,
zrc20,
amount - inputForGas,
params.target,
0
);
// Approve the target token for withdrawal
IZRC20(gasZRC20).approve(params.target, gasFee);
// Withdraw the target token to the recipient
IZRC20(params.target).withdraw(params.to, outputAmount);
}
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
(gasZRC20, gasFee) = IZRC20(params.target).withdrawGasFee(); | |
inputForGas = SwapHelperLib.swapTokensForExactTokens( | |
systemContract, | |
inputToken, | |
zrc20, | |
gasFee, | |
gasZRC20, | |
amount | |
); | |
uint256 outputAmount = SwapHelperLib.swapExactTokensForTokens( | |
systemContract, | |
inputToken, | |
zrc20, | |
amount - inputForGas, | |
targetToken, | |
params.target, | |
0 | |
); | |
IZRC20(gasZRC20).approve(targetToken, gasFee); | |
IZRC20(targetToken).withdraw(recipient, outputAmount); | |
IZRC20(gasZRC20).approve(params.target, gasFee); | |
IZRC20(params.target).withdraw(params.to, outputAmount); | |
function onCrossChainCall( | |
zContext calldata context, | |
address zrc20, | |
uint256 amount, | |
bytes calldata message | |
) external virtual override onlySystem(systemContract) { | |
Params memory params = Params({target: address(0), to: bytes("")}); | |
if (context.chainID == BITCOIN) { | |
params.target = BytesHelperLib.bytesToAddress(message, 0); | |
params.to = abi.encodePacked( | |
BytesHelperLib.bytesToAddress(message, 20) | |
); | |
} else { | |
(address targetToken, bytes memory recipient) = abi.decode( | |
message, | |
(address, bytes) | |
); | |
params.target = targetToken; | |
params.to = recipient; | |
} | |
uint256 inputForGas; | |
address gasZRC20; | |
uint256 gasFee; | |
// Retrieve the gas fee for the target token | |
(gasZRC20, gasFee) = IZRC20(params.target).withdrawGasFee(); | |
// Swap tokens for the exact amount of gas fee | |
inputForGas = SwapHelperLib.swapTokensForExactTokens( | |
systemContract, | |
zrc20, | |
gasFee, | |
gasZRC20, | |
amount | |
); | |
// Swap the remaining tokens for the target token | |
uint256 outputAmount = SwapHelperLib.swapExactTokensForTokens( | |
systemContract, | |
zrc20, | |
amount - inputForGas, | |
params.target, | |
0 | |
); | |
// Approve the target token for withdrawal | |
IZRC20(gasZRC20).approve(params.target, gasFee); | |
// Withdraw the target token to the recipient | |
IZRC20(params.target).withdraw(params.to, outputAmount); | |
} |
Solana -> ZetaChain:
https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inTxHashToCctxData/4415FPh1cceJ1NtBAuFEWnnp9pV8YhN1EQVvydG83KVhfhSzB8WWX1Qi4HF84yvwAcCqVsNu1rAAHCN43GdAbbYX
ZetaChain -> Ethereum Sepolia:
https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/cctx/0xd8e59d0b3ea1b34dc6b0b5ae3563864f59a0a969aea2e60be95e977c1f04cfe0
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores