-
Notifications
You must be signed in to change notification settings - Fork 60
/
TransferUSDCBase.sol
133 lines (110 loc) · 4.56 KB
/
TransferUSDCBase.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// Deploy this contract on Base Sepolia
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";
import {SafeERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/token/ERC20/utils/SafeERC20.sol";
interface USDCInterface {
function approve(address spender, uint256 value) external;
}
/**
* THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract TransferUSDCBase {
using SafeERC20 for IERC20;
error NotEnoughBalanceForFees(uint256 currentBalance, uint256 calculatedFees);
error NotEnoughBalanceUsdcForTransfer(uint256 currentBalance);
error NothingToWithdraw();
address public owner;
IRouterClient private immutable ccipRouter;
IERC20 private immutable linkToken;
IERC20 private immutable usdcToken;
// https://docs.chain.link/ccip/supported-networks/v1_2_0/testnet#base-sepolia
address ccipRouterAddress = 0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93;
// https://docs.chain.link/resources/link-token-contracts#base-sepolia-testnet
address linkAddress = 0xE4aB69C077896252FAFBD49EFD26B5D171A32410;
// https://developers.circle.com/stablecoins/docs/usdc-on-test-networks
// https://base-sepolia.blockscout.com/address/0x036CbD53842c5426634e7929541eC2318f3dCF7e
address usdcAddress = 0x036CbD53842c5426634e7929541eC2318f3dCF7e;
// https://docs.chain.link/ccip/supported-networks/v1_2_0/testnet#ethereum-sepolia
uint64 destinationChainSelector = 16015286601757825753;
event UsdcTransferred(
bytes32 messageId,
uint64 destinationChainSelector,
address receiver,
uint256 amount,
uint256 ccipFee
);
constructor() {
owner = msg.sender;
ccipRouter = IRouterClient(ccipRouterAddress);
linkToken = IERC20(linkAddress);
usdcToken = IERC20(usdcAddress);
}
function transferUsdcToSepolia(
address _receiver,
uint256 _amount
)
external
returns (bytes32 messageId)
{
Client.EVMTokenAmount[]
memory tokenAmounts = new Client.EVMTokenAmount[](1);
Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({
token: address(usdcToken),
amount: _amount
});
tokenAmounts[0] = tokenAmount;
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(_receiver),
data: "",
tokenAmounts: tokenAmounts,
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({gasLimit: 0})
),
feeToken: address(linkToken)
});
uint256 ccipFee = ccipRouter.getFee(
destinationChainSelector,
message
);
if (ccipFee > linkToken.balanceOf(address(this)))
revert NotEnoughBalanceForFees(linkToken.balanceOf(address(this)), ccipFee);
linkToken.approve(address(ccipRouter), ccipFee);
if (_amount > usdcToken.balanceOf(msg.sender))
revert NotEnoughBalanceUsdcForTransfer(usdcToken.balanceOf(msg.sender));
usdcToken.safeTransferFrom(msg.sender, address(this), _amount);
usdcToken.approve(address(ccipRouter), _amount);
// Send CCIP Message
messageId = ccipRouter.ccipSend(destinationChainSelector, message);
emit UsdcTransferred(
messageId,
destinationChainSelector,
_receiver,
_amount,
ccipFee
);
}
function allowanceUsdc() public view returns (uint256 usdcAmount) {
usdcAmount = usdcToken.allowance(msg.sender, address(this));
}
function balancesOf(address account) public view returns (uint256 linkBalance, uint256 usdcBalance) {
linkBalance = linkToken.balanceOf(account);
usdcBalance = IERC20(usdcToken).balanceOf(account);
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function withdrawToken(
address _beneficiary,
address _token
) public onlyOwner {
uint256 amount = IERC20(_token).balanceOf(address(this));
if (amount == 0) revert NothingToWithdraw();
IERC20(_token).transfer(_beneficiary, amount);
}
}