Skip to content

Commit 8ca49c1

Browse files
committed
feat: add wip, L1 gateway
1 parent a525c52 commit 8ca49c1

File tree

2 files changed

+62
-18
lines changed

2 files changed

+62
-18
lines changed

packages/solidity-contracts/contracts/messaging/gateway/FuelERC20Gateway/FuelERC20GatewayV4.sol

+50-18
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ contract FuelERC20GatewayV4 is
5050
// Constants //
5151
///////////////
5252

53-
bytes1 public constant DEPOSIT_TO_CONTRACT = bytes1(keccak256("DEPOSIT_TO_CONTRACT"));
54-
5553
/// @dev The admin related contract roles
5654
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
5755
uint256 public constant FUEL_ASSET_DECIMALS = 9;
@@ -107,6 +105,7 @@ contract FuelERC20GatewayV4 is
107105
}
108106

109107
/// @notice see `requireWhitelist`
108+
/// @dev param `limit` must be down/up scaled according to _adjustDepositDecimals
110109
function setGlobalDepositLimit(address token, uint256 limit) external payable virtual onlyRole(DEFAULT_ADMIN_ROLE) {
111110
_depositLimits[token] = limit;
112111
}
@@ -143,18 +142,18 @@ contract FuelERC20GatewayV4 is
143142
/// @dev Made payable to reduce gas costs
144143
function deposit(bytes32 to, address tokenAddress, uint256 amount) external payable virtual whenNotPaused {
145144
uint8 decimals = _getTokenDecimals(tokenAddress);
145+
uint256 l2MintedAmount = _adjustDepositDecimals(decimals, amount);
146146

147147
bytes memory messageData = abi.encodePacked(
148-
MessageType.DEPOSIT,
149148
assetIssuerId,
149+
MessageType.DEPOSIT,
150150
bytes32(uint256(uint160(tokenAddress))),
151151
bytes32(0),
152152
bytes32(uint256(uint160(msg.sender))),
153153
to,
154-
amount,
155-
decimals
154+
l2MintedAmount
156155
);
157-
_deposit(tokenAddress, amount, messageData);
156+
_deposit(tokenAddress, amount, l2MintedAmount, messageData);
158157
}
159158

160159
/// @notice Deposits the given tokens to a contract on Fuel with optional data
@@ -170,45 +169,56 @@ contract FuelERC20GatewayV4 is
170169
bytes calldata data
171170
) external payable virtual whenNotPaused {
172171
uint8 decimals = _getTokenDecimals(tokenAddress);
172+
uint256 l2MintedAmount = _adjustDepositDecimals(decimals, amount);
173173

174174
bytes memory messageData = abi.encodePacked(
175-
MessageType.DEPOSIT,
176175
assetIssuerId,
176+
MessageType.DEPOSIT,
177177
bytes32(uint256(uint160(tokenAddress))),
178178
bytes32(0),
179179
bytes32(uint256(uint160(msg.sender))),
180180
to,
181-
amount,
182-
decimals,
183-
DEPOSIT_TO_CONTRACT,
181+
l2MintedAmount,
184182
data
185183
);
186-
_deposit(tokenAddress, amount, messageData);
184+
_deposit(tokenAddress, amount, l2MintedAmount, messageData);
187185
}
188186

189187
function sendMetadata(address tokenAddress) external payable virtual whenNotPaused {
190188
bytes memory messageData = abi.encodePacked(
189+
assetIssuerId,
191190
MessageType.METADATA,
192-
abi.encode(IERC20MetadataUpgradeable(tokenAddress).symbol(), IERC20MetadataUpgradeable(tokenAddress).name())
191+
abi.encode(
192+
tokenAddress,
193+
uint256(0), // token_id = 0 for all erc20 deposits
194+
IERC20MetadataUpgradeable(tokenAddress).symbol(),
195+
IERC20MetadataUpgradeable(tokenAddress).name()
196+
)
193197
);
194198
sendMessage(CommonPredicates.CONTRACT_MESSAGE_PREDICATE, messageData);
195199
}
196200

197201
/// @notice Deposits the given tokens to an account or contract on Fuel
198202
/// @param tokenAddress Address of the token being transferred to Fuel
199-
/// @param amount Amount of tokens to deposit
203+
/// @param amount tokens that have been deposited
204+
/// @param l2MintedAmount tokens that will be minted on L2
200205
/// @param messageData The data of the message to send for deposit
201-
function _deposit(address tokenAddress, uint256 amount, bytes memory messageData) internal virtual {
206+
function _deposit(
207+
address tokenAddress,
208+
uint256 amount,
209+
uint256 l2MintedAmount,
210+
bytes memory messageData
211+
) internal virtual {
202212
////////////
203213
// Checks //
204214
////////////
205-
if (amount == 0) revert CannotDepositZero();
206-
if (amount > uint256(type(uint64).max)) revert CannotDepositZero();
215+
if (l2MintedAmount == 0) revert CannotDepositZero();
216+
if (l2MintedAmount > uint256(type(uint64).max)) revert CannotDepositZero();
207217

208218
/////////////
209219
// Effects //
210220
/////////////
211-
uint256 updatedDeposits = _deposits[tokenAddress] + amount;
221+
uint256 updatedDeposits = _deposits[tokenAddress] + l2MintedAmount;
212222
if (updatedDeposits > type(uint64).max) revert BridgeFull();
213223

214224
if (whitelistRequired && updatedDeposits > _depositLimits[tokenAddress]) {
@@ -274,7 +284,7 @@ contract FuelERC20GatewayV4 is
274284
return uint8(decimals);
275285
}
276286

277-
function _adjustDecimals(uint8 tokenDecimals, uint256 amount) internal virtual returns (uint256) {
287+
function _adjustDepositDecimals(uint8 tokenDecimals, uint256 amount) internal pure virtual returns (uint256) {
278288
// Most common case: less than 9 decimals (USDT, USDC, WBTC)
279289
if (tokenDecimals < 9) {
280290
return amount * (10 ** (9 - tokenDecimals));
@@ -295,6 +305,28 @@ contract FuelERC20GatewayV4 is
295305
return amount;
296306
}
297307

308+
function _adjustWithdrawalDecimals(uint8 tokenDecimals, uint256 amount) internal pure virtual returns (uint256) {
309+
unchecked {
310+
if (tokenDecimals < 9) {
311+
// Subject to precision losses (dust) in L2
312+
// Economic losses due to this are estimated to be less
313+
// than other evaluated alternatives, such as:
314+
// - bouncing the deposit back to L2. E.g., in order to lose in the order of 0.01 USD
315+
// BTC price should be sitting at 500k USDBTC
316+
// - storing decimals in L2
317+
return divByNonZero(amount, 10 ** (9 - tokenDecimals));
318+
}
319+
}
320+
321+
if (tokenDecimals > 9) {
322+
uint256 precision = 10 ** (tokenDecimals - 9);
323+
return amount * precision;
324+
}
325+
326+
return amount;
327+
}
328+
329+
/// @dev gas efficient division. Must be used with care, `_div` must be non zero
298330
function divByNonZero(uint256 _num, uint256 _div) internal pure returns (uint256 result) {
299331
assembly {
300332
result := div(_num, _div)

packages/solidity-contracts/test/behaviors/erc20GatewayV4.behavior.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -655,5 +655,17 @@ export function behavesLikeErc20GatewayV4(fixture: () => Promise<Env>) {
655655
);
656656
});
657657
});
658+
659+
describe('sendMetadata()', () => {
660+
describe('when paused', () => {
661+
it('reverts');
662+
});
663+
664+
it('works', async () => {
665+
const { erc20Gateway, token } = env;
666+
667+
await erc20Gateway.sendMetadata(token);
668+
});
669+
});
658670
});
659671
}

0 commit comments

Comments
 (0)