1
+ // SPDX-License-Identifier: MIT OR Apache-2.0
2
+ pragma solidity ^ 0.8.26 ;
3
+
4
+ import {InterchainTokenExecutable} from "@axelar-network/interchain-token-service/contracts/executable/InterchainTokenExecutable.sol " ;
5
+ import {IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
6
+ import {SubnetID} from "@ipc/contracts/contracts/structs/Subnet.sol " ;
7
+ import {FvmAddress} from "@ipc/contracts/contracts/structs/FvmAddress.sol " ;
8
+ import {IGateway} from "@ipc/contracts/contracts/interfaces/IGateway.sol " ;
9
+
10
+ /// @title AutoDeposit
11
+ /// @notice Handles automatic token deposits from Axelar to IPC subnets
12
+ /// @dev Implements InterchainTokenExecutable for cross-chain token transfers
13
+ contract AutoDeposit is InterchainTokenExecutable {
14
+ error WrongToken (address received , address expected );
15
+ error TokenApprovalFailed (address token , address spender , uint256 amount );
16
+
17
+ SubnetID public recallSubnet;
18
+ IERC20 public immutable RECALL_TOKEN;
19
+ IGateway public immutable RECALL_GATEWAY;
20
+
21
+ /// @notice Initializes the contract with required addresses and subnet ID
22
+ /// @param subnet The subnet ID where tokens will be deposited
23
+ /// @param token The address of the token to be handled
24
+ /// @param gateway The address of the IPC gateway
25
+ /// @param interchainTokenService_ The address of Axelar's interchain token service
26
+ constructor (
27
+ SubnetID memory subnet ,
28
+ address token ,
29
+ address gateway ,
30
+ address interchainTokenService_
31
+ ) InterchainTokenExecutable (interchainTokenService_) {
32
+ recallSubnet = subnet;
33
+ RECALL_TOKEN = IERC20 (token);
34
+ RECALL_GATEWAY = IGateway (gateway);
35
+ }
36
+
37
+ /// @inheritdoc InterchainTokenExecutable
38
+ function _executeWithInterchainToken (
39
+ bytes32 , // commandId
40
+ string calldata , // sourceChain
41
+ bytes calldata , // sourceAddress
42
+ bytes calldata data ,
43
+ bytes32 , // tokenId
44
+ address token ,
45
+ uint256 amount
46
+ ) internal override {
47
+ if (token != address (RECALL_TOKEN)) {
48
+ revert WrongToken (token, address (RECALL_TOKEN));
49
+ }
50
+
51
+ bool success = RECALL_TOKEN.approve (address (RECALL_GATEWAY), amount);
52
+ if (! success) {
53
+ revert TokenApprovalFailed (address (RECALL_TOKEN), address (RECALL_GATEWAY), amount);
54
+ }
55
+
56
+ address recipient = abi.decode (data, (address ));
57
+ FvmAddress memory fvmAddress = convertToFvmAddr (recipient);
58
+
59
+ SubnetID memory subnetCopy;
60
+ subnetCopy.root = recallSubnet.root;
61
+ subnetCopy.route = new address [](recallSubnet.route.length );
62
+ for (uint256 i = 0 ; i < recallSubnet.route.length ; i++ ) {
63
+ subnetCopy.route[i] = recallSubnet.route[i];
64
+ }
65
+
66
+ RECALL_GATEWAY.fundWithToken ({
67
+ subnetId: subnetCopy,
68
+ to: fvmAddress,
69
+ amount: amount
70
+ });
71
+ }
72
+
73
+ /// @notice Converts an Ethereum address to FVM address format
74
+ /// @param _addr The Ethereum address to convert
75
+ /// @return FVM formatted address
76
+ function convertToFvmAddr (address _addr ) internal pure returns (FvmAddress memory ) {
77
+ return FvmAddress ({
78
+ addrType: 1 , // f1 address type
79
+ payload: abi.encodePacked (_addr)
80
+ });
81
+ }
82
+ }
0 commit comments