import { getNetworkNameForEid, types } from '@layerzerolabs/devtools-evm-hardhat';
import type { EndpointId } from '@layerzerolabs/lz-definitions';
import { addressToBytes32 } from '@layerzerolabs/lz-v2-utilities';
import { Options } from '@layerzerolabs/lz-v2-utilities';
import type { BigNumberish, BytesLike } from 'ethers';
import { task } from 'hardhat/config';
const HELPER_ABI = [
"function send(address oftContract, tuple(uint32 dstEid, bytes to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd) sendParam) external returns (tuple(bytes32 guid, uint256 nonce, bytes32 recipient, bytes message), tuple(uint256 amountLD, uint256 minAmountLD))",
"function addressToBytes32(address _addr) external pure returns (bytes32)"
];
const HELPER_ADDRESS = "0x88172F3041Bd0787520dbc9Bd33D3d48e1fb46dc";
interface Args {
amount: string;
to: string;
toEid: EndpointId;
sophon?: boolean;
}
interface SendParam {
dstEid: EndpointId;
to: BytesLike;
amountLD: BigNumberish;
minAmountLD: BigNumberish;
extraOptions: BytesLike;
composeMsg: BytesLike;
oftCmd: BytesLike;
}
task('lz:oft:send', 'Sends tokens from either OFT or OFTAdapter')
.addParam('to', 'contract address on network B', undefined, types.string)
.addParam('toEid', 'destination endpoint ID', undefined, types.eid)
.addParam('amount', 'amount to transfer in token decimals', undefined, types.string)
.addOptionalParam('sophon', 'use LzOftHelper for Sophon network', false, types.boolean)
.setAction(async (taskArgs: Args, { ethers, deployments }) => {
const toAddress = taskArgs.to;
const eidB = taskArgs.toEid;
const oftDeployment = await deployments.get('MyOFT');
const [signer] = await ethers.getSigners();
const oftContract = new ethers.Contract(oftDeployment.address, oftDeployment.abi, signer);
const helperContract = new ethers.Contract(HELPER_ADDRESS, HELPER_ABI, signer);
const decimals = await oftContract.decimals();
const amount = ethers.utils.parseUnits(taskArgs.amount, decimals);
const options = Options.newOptions().addExecutorLzReceiveOption(65000, 0).toBytes();
const oft = oftContract;
const sendParam: SendParam = {
dstEid: eidB,
to: addressToBytes32(toAddress),
amountLD: amount,
minAmountLD: amount,
extraOptions: options,
composeMsg: ethers.utils.arrayify('0x'),
oftCmd: ethers.utils.arrayify('0x'),
};
console.log(
`sending ${taskArgs.amount} token(s) to network ${getNetworkNameForEid(eidB)} (${eidB})`
);
if (taskArgs.sophon) {
const innerTokenAddress = await oft.token();
const ERC20Factory = await ethers.getContractFactory('ERC20');
const innerToken = ERC20Factory.attach(innerTokenAddress);
await innerToken.approve(helperContract.address, amount);
const tx = await helperContract.send(oftContract.address, sendParam);
console.log(`Send tx initiated via helper. See: https://layerzeroscan.com/tx/${tx.hash}`);
} else {
const feeQuote = await oft.quoteSend(sendParam, false);
const nativeFee = feeQuote.nativeFee;
console.log(
`sending ${taskArgs.amount} token(s) to network ${getNetworkNameForEid(eidB)} (${eidB})`,
);
const ERC20Factory = await ethers.getContractFactory('ERC20');
const innerTokenAddress = await oft.token();
const r = await oft.send(sendParam, {nativeFee: nativeFee, lzTokenFee: 0}, signer.address, {
value: nativeFee,
});
console.log(`Send tx initiated directly. See: https://layerzeroscan.com/tx/${r.hash}`);
}
});