-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathAxelarGasService.sol
183 lines (157 loc) · 5.85 KB
/
AxelarGasService.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import { IAxelarGasService } from '../interfaces/IAxelarGasService.sol';
import { IERC20 } from '../interfaces/IERC20.sol';
import '../util/Upgradable.sol';
// This should be owned by the microservice that is paying for gas.
contract AxelarGasService is Upgradable, IAxelarGasService {
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
_safeTransferFrom(gasToken, msg.sender, gasFeeAmount);
emit GasPaidForContractCall(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
gasToken,
gasFeeAmount,
refundAddress
);
}
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string memory symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
_safeTransferFrom(gasToken, msg.sender, gasFeeAmount);
emit GasPaidForContractCallWithToken(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
symbol,
amount,
gasToken,
gasFeeAmount,
refundAddress
);
}
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable override {
if (msg.value == 0) revert NothingReceived();
emit NativeGasPaidForContractCall(sender, destinationChain, destinationAddress, keccak256(payload), msg.value, refundAddress);
}
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable override {
if (msg.value == 0) revert NothingReceived();
emit NativeGasPaidForContractCallWithToken(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
symbol,
amount,
msg.value,
refundAddress
);
}
function addGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
_safeTransferFrom(gasToken, msg.sender, gasFeeAmount);
emit GasAdded(txHash, logIndex, gasToken, gasFeeAmount, refundAddress);
}
function addNativeGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable override {
if (msg.value == 0) revert NothingReceived();
emit NativeGasAdded(txHash, logIndex, msg.value, refundAddress);
}
function collectFees(address payable receiver, address[] calldata tokens) external onlyOwner {
if (receiver == address(0)) revert InvalidAddress();
for (uint256 i; i < tokens.length; i++) {
address token = tokens[i];
if (token == address(0)) {
uint256 amount = address(this).balance;
if (amount > 0) receiver.transfer(amount);
} else {
uint256 amount = IERC20(token).balanceOf(address(this));
if (amount > 0) _safeTransfer(token, receiver, amount);
}
}
}
function refund(
address payable receiver,
address token,
uint256 amount
) external onlyOwner {
if (receiver == address(0)) revert InvalidAddress();
if (token == address(0)) {
receiver.transfer(amount);
} else {
_safeTransfer(token, receiver, amount);
}
}
function _safeTransfer(
address tokenAddress,
address receiver,
uint256 amount
) internal {
if (amount == 0) revert NothingReceived();
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returnData) = tokenAddress.call(abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount));
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || tokenAddress.code.length == 0) revert TransferFailed();
}
function _safeTransferFrom(
address tokenAddress,
address from,
uint256 amount
) internal {
if (amount == 0) revert NothingReceived();
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returnData) = tokenAddress.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, address(this), amount)
);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || tokenAddress.code.length == 0) revert TransferFailed();
}
function contractId() external pure returns (bytes32) {
return keccak256('axelar-gas-service');
}
}