Skip to content

Commit 7d05406

Browse files
authored
feat: add support for contract calls through intent (#25)
* change contract logic * add test * format * skip gas payment when target is zetachain * add intent proxy deployment script * fmt * use transfer instead of approve * remove try initiate * add call support * fix tests * add example contract * fmt * fix file * add initiateTransfer * add fulfillTransfer * add intent call tests * support ciustom gas limit * a few fix * fix imports * remove nonReentrant * increase default gas limit
1 parent 3631d14 commit 7d05406

File tree

12 files changed

+1817
-64
lines changed

12 files changed

+1817
-64
lines changed

examples/CrossChainSwapper.sol

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.26;
3+
4+
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5+
import "@openzeppelin/contracts/access/Ownable.sol";
6+
import "../src/interfaces/IntentTarget.sol";
7+
8+
// Uniswap V2 Router interface (partial)
9+
interface IUniswapV2Router {
10+
function swapExactTokensForTokens(
11+
uint256 amountIn,
12+
uint256 amountOutMin,
13+
address[] calldata path,
14+
address to,
15+
uint256 deadline
16+
) external returns (uint256[] memory amounts);
17+
}
18+
19+
/**
20+
* @title CrossChainSwapper
21+
* @dev Example implementation of IntentTarget that performs token swaps
22+
*/
23+
contract CrossChainSwapper is IntentTarget, Ownable {
24+
// Uniswap V2 Router address
25+
address public uniswapRouter;
26+
27+
// Reward configuration
28+
uint256 public rewardPercentage = 5; // 5% reward to fulfillers
29+
30+
/**
31+
* @dev Constructor
32+
* @param _uniswapRouter The Uniswap V2 Router address
33+
*/
34+
constructor(address _uniswapRouter) Ownable(msg.sender) {
35+
uniswapRouter = _uniswapRouter;
36+
}
37+
38+
/**
39+
* @dev Update the Uniswap router address
40+
* @param _uniswapRouter The new router address
41+
*/
42+
function setUniswapRouter(address _uniswapRouter) external onlyOwner {
43+
uniswapRouter = _uniswapRouter;
44+
}
45+
46+
/**
47+
* @dev Set reward percentage for fulfillers
48+
* @param _percentage New percentage (0-100)
49+
*/
50+
function setRewardPercentage(uint256 _percentage) external onlyOwner {
51+
require(_percentage <= 100, "Percentage must be between 0-100");
52+
rewardPercentage = _percentage;
53+
}
54+
55+
/**
56+
* @dev Called by the protocol during intent fulfillment
57+
* @param intentId The ID of the intent
58+
* @param asset The ERC20 token address
59+
* @param amount Amount transferred
60+
* @param data Custom data for execution
61+
*/
62+
function onFulfill(
63+
bytes32 intentId,
64+
address asset,
65+
uint256 amount,
66+
bytes calldata data
67+
) external override {
68+
// Decode the swap parameters from the data field
69+
(
70+
address[] memory path,
71+
uint256 minAmountOut,
72+
uint256 deadline,
73+
address receiver
74+
) = decodeSwapParams(data);
75+
76+
// Ensure the first token in the path matches the received asset
77+
require(path[0] == asset, "Asset mismatch");
78+
79+
// Approve router to spend the tokens
80+
IERC20(asset).approve(uniswapRouter, amount);
81+
82+
// Execute the swap on Uniswap
83+
IUniswapV2Router(uniswapRouter).swapExactTokensForTokens(
84+
amount,
85+
minAmountOut,
86+
path,
87+
receiver,
88+
deadline
89+
);
90+
}
91+
92+
/**
93+
* @dev Called by the protocol during intent settlement
94+
* @param intentId The ID of the intent
95+
* @param asset The ERC20 token address
96+
* @param amount Amount transferred
97+
* @param data Custom data for execution
98+
* @param fulfillmentIndex The fulfillment index for this intent
99+
*/
100+
function onSettle(
101+
bytes32 intentId,
102+
address asset,
103+
uint256 amount,
104+
bytes calldata data,
105+
bytes32 fulfillmentIndex
106+
) external override {
107+
// This function is called when an intent is settled
108+
// We can implement custom logic here, such as rewarding the fulfiller
109+
110+
// We could send a small reward to the fulfiller from this contract's balance
111+
// This might be tokens previously sent to this contract for this purpose
112+
113+
// Example: get receiver address from the data
114+
(, , , address receiver) = decodeSwapParams(data);
115+
116+
// Example: transfer a small reward from this contract to the fulfiller
117+
// This assumes this contract holds some tokens for rewards
118+
// In a real implementation, you might have a more sophisticated reward system
119+
120+
// Get fulfiller address from the Intent contract (passed as msg.sender)
121+
address intentContract = msg.sender;
122+
123+
// Note: In a real implementation, you would have a way to get the fulfiller address
124+
// For this example, we're just showing the concept
125+
// Normally, you could call a view function on the Intent contract to get the fulfiller
126+
}
127+
128+
/**
129+
* @dev Helper function to decode swap parameters from the bytes data
130+
* @param data The encoded swap parameters
131+
* @return path Array of token addresses for the swap path
132+
* @return minAmountOut Minimum output amount
133+
* @return deadline Transaction deadline
134+
* @return receiver Address that will receive the swapped tokens
135+
*/
136+
function decodeSwapParams(
137+
bytes memory data
138+
)
139+
internal
140+
pure
141+
returns (
142+
address[] memory path,
143+
uint256 minAmountOut,
144+
uint256 deadline,
145+
address receiver
146+
)
147+
{
148+
// Decode the packed data
149+
return abi.decode(data, (address[], uint256, uint256, address));
150+
}
151+
152+
/**
153+
* @dev Helper function to encode swap parameters
154+
* @param path Array of token addresses for the swap path
155+
* @param minAmountOut Minimum output amount
156+
* @param deadline Transaction deadline
157+
* @param receiver Address that will receive the swapped tokens
158+
* @return The encoded parameters as bytes
159+
*/
160+
function encodeSwapParams(
161+
address[] memory path,
162+
uint256 minAmountOut,
163+
uint256 deadline,
164+
address receiver
165+
) public pure returns (bytes memory) {
166+
return abi.encode(path, minAmountOut, deadline, receiver);
167+
}
168+
}

0 commit comments

Comments
 (0)