Skip to content

Commit

Permalink
call: withdraw and call arbitrary
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev committed Nov 11, 2024
1 parent c2410f0 commit ed3e800
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 52 deletions.
20 changes: 10 additions & 10 deletions examples/call/contracts/Connected.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@ contract Connected {
gateway = GatewayEVM(gatewayAddress);
}

function hello(string memory message) external payable {
emit HelloEvent("Hello on EVM", message);
}

function onRevert(
RevertContext calldata revertContext
) external onlyGateway {
emit RevertEvent("Revert on EVM", revertContext);
}

function deposit(
address receiver,
RevertOptions memory revertOptions
Expand Down Expand Up @@ -56,6 +46,10 @@ contract Connected {
);
}

function hello(string memory message) external payable {
emit HelloEvent("Hello on EVM", message);
}

function onCall(
MessageContext calldata context,
bytes calldata message
Expand All @@ -65,6 +59,12 @@ contract Connected {
return "";
}

function onRevert(
RevertContext calldata revertContext
) external onlyGateway {
emit RevertEvent("Revert on EVM", revertContext);
}

receive() external payable {}

fallback() external payable {}
Expand Down
68 changes: 34 additions & 34 deletions examples/call/contracts/Universal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,6 @@ contract Universal is UniversalContract {
gateway = GatewayZEVM(gatewayAddress);
}

function onCall(
MessageContext calldata context,
address zrc20,
uint256 amount,
bytes calldata message
) external override onlyGateway {
string memory name = abi.decode(message, (string));
emit HelloEvent("Hello on ZetaChain", name);
}

function onRevert(
RevertContext calldata revertContext
) external onlyGateway {
emit RevertEvent("Revert on ZetaChain", revertContext);
}

function call(
bytes memory receiver,
address zrc20,
bytes calldata message,
uint256 gasLimit,
RevertOptions memory revertOptions
) external {
(, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit);
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee))
revert TransferFailed();
IZRC20(zrc20).approve(address(gateway), gasFee);
CallOptions memory callOptions = CallOptions(gasLimit, true);
gateway.call(receiver, zrc20, message, callOptions, revertOptions);
}

function withdraw(
bytes memory receiver,
uint256 amount,
Expand All @@ -77,16 +46,32 @@ contract Universal is UniversalContract {
gateway.withdraw(receiver, amount, zrc20, revertOptions);
}

Check warning

Code scanning / Slither

Unused return Medium

Check warning

Code scanning / Slither

Unused return Medium


function call(
bytes memory receiver,
address zrc20,
bytes calldata message,
CallOptions memory callOptions,
RevertOptions memory revertOptions
) external {
(, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(
callOptions.gasLimit
);
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee))
revert TransferFailed();
IZRC20(zrc20).approve(address(gateway), gasFee);
gateway.call(receiver, zrc20, message, callOptions, revertOptions);
}

function withdrawAndCall(
bytes memory receiver,
uint256 amount,
address zrc20,
bytes calldata message,
uint256 gasLimit,
CallOptions memory callOptions,
RevertOptions memory revertOptions
) external {
(address gasZRC20, uint256 gasFee) = IZRC20(zrc20)
.withdrawGasFeeWithGasLimit(gasLimit);
.withdrawGasFeeWithGasLimit(callOptions.gasLimit);
uint256 target = zrc20 == gasZRC20 ? amount + gasFee : amount;
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), target))
revert TransferFailed();
Expand All @@ -101,7 +86,6 @@ contract Universal is UniversalContract {
) revert TransferFailed();
IZRC20(gasZRC20).approve(address(gateway), gasFee);
}
CallOptions memory callOptions = CallOptions(gasLimit, false);
gateway.withdrawAndCall(
receiver,
amount,
Expand All @@ -111,4 +95,20 @@ contract Universal is UniversalContract {
revertOptions
);
}

function onCall(
MessageContext calldata context,
address zrc20,
uint256 amount,
bytes calldata message
) external override onlyGateway {
string memory name = abi.decode(message, (string));
emit HelloEvent("Hello on ZetaChain", name);
}

function onRevert(
RevertContext calldata revertContext
) external onlyGateway {
emit RevertEvent("Revert on ZetaChain", revertContext);
}
}
11 changes: 11 additions & 0 deletions examples/call/scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ npx hardhat universal-withdraw-and-call \
--function "hello(string)" \
--amount 1 \
--network localhost \
--call-options-is-arbitrary-call \
--types '["string"]' hello

npx hardhat localnet-check

npx hardhat universal-withdraw-and-call \
--contract "$CONTRACT_ZETACHAIN" \
--receiver "$CONTRACT_ETHEREUM" \
--zrc20 "$ZRC20_ETHEREUM" \
--amount 1 \
--network localhost \
--types '["string"]' hello

npx hardhat localnet-check
Expand Down
14 changes: 13 additions & 1 deletion examples/call/tasks/universalCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
gasLimit: args.txOptionsGasLimit,
};

const callOptions = {
isArbitraryCall: args.callOptionsIsArbitraryCall,
gasLimit: args.callOptionsGasLimit,
};

const revertOptions = {
abortAddress: "0x0000000000000000000000000000000000000000", // not used
callOnRevert: args.callOnRevert,
Expand Down Expand Up @@ -69,7 +74,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
ethers.utils.hexlify(args.receiver),
args.zrc20,
message,
gasLimit,
callOptions,
revertOptions,
txOptions
);
Expand Down Expand Up @@ -114,6 +119,13 @@ task(
7000000,
types.int
)
.addFlag("callOptionsIsArbitraryCall", "Call any function")
.addOptionalParam(
"callOptionsGasLimit",
"The gas limit for the call",
7000000,
types.int
)
.addParam("function", `Function to call (example: "hello(string)")`)
.addParam("name", "The name of the contract", "Universal")
.addParam("types", `The types of the parameters (example: '["string"]')`)
Expand Down
39 changes: 32 additions & 7 deletions examples/call/tasks/universalWithdrawAndCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,24 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
const { ethers } = hre;
const [signer] = await ethers.getSigners();

if (args.callOptionsIsArbitraryCall && !args.function) {
throw new Error("Function is required for arbitrary calls");
}

if (!args.callOptionsIsArbitraryCall && args.function) {
throw new Error("Function is not allowed for non-arbitrary calls");
}

const txOptions = {
gasPrice: args.txOptionsGasPrice,
gasLimit: args.txOptionsGasLimit,
};

const callOptions = {
isArbitraryCall: args.callOptionsIsArbitraryCall,
gasLimit: args.callOptionsGasLimit,
};

const revertOptions = {
abortAddress: "0x0000000000000000000000000000000000000000", // not used
callOnRevert: args.callOnRevert,
Expand All @@ -21,8 +34,6 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
),
};

const functionSignature = ethers.utils.id(args.function).slice(0, 10);

const types = JSON.parse(args.types);

if (types.length !== args.values.length) {
Expand Down Expand Up @@ -51,9 +62,16 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
valuesArray
);

const message = ethers.utils.hexlify(
ethers.utils.concat([functionSignature, encodedParameters])
);
let message;

if (args.isArbitraryCall) {
let functionSignature = ethers.utils.id(args.function).slice(0, 10);
message = ethers.utils.hexlify(
ethers.utils.concat([functionSignature, encodedParameters])
);
} else {
message = encodedParameters;
}

const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit);

Expand Down Expand Up @@ -86,7 +104,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
amount,
args.zrc20,
message,
gasLimit,
callOptions,
revertOptions,
txOptions
);
Expand Down Expand Up @@ -132,7 +150,14 @@ task(
7000000,
types.int
)
.addParam("function", `Function to call (example: "hello(string)")`)
.addFlag("callOptionsIsArbitraryCall", "Call any function")
.addOptionalParam(
"callOptionsGasLimit",
"The gas limit for the call",
7000000,
types.int
)
.addOptionalParam("function", `Function to call (example: "hello(string)")`)
.addParam("name", "The name of the contract", "Universal")
.addParam("amount", "Amount of ZRC-20 to withdraw")
.addParam("types", `The types of the parameters (example: '["string"]')`)
Expand Down

0 comments on commit ed3e800

Please sign in to comment.