Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce decimals record for L2 #166

Merged
merged 2 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/grumpy-cheetahs-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@fuel-bridge/solidity-contracts': patch
'@fuel-bridge/fungible-token': patch
---

Use L1 token decimals to determine L2 token decimals
17 changes: 13 additions & 4 deletions packages/fungible-token/bridge-fungible-token/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,10 @@ use utils::{
};
use src_20::SRC20;

const DEFAULT_DECIMALS: u8 = 9u8;
const FUEL_ASSET_DECIMALS: u8 = 9u8;
const ZERO_U256 = 0x00u256;

configurable {
DECIMALS: u64 = 9u64,
BRIDGED_TOKEN_GATEWAY: b256 = 0x00000000000000000000000096c53cd98B7297564716a8f2E1de2C83928Af2fe,
}

Expand All @@ -74,6 +73,7 @@ storage {
l1_addresses: StorageMap<AssetId, b256> = StorageMap {},
l1_symbols: StorageMap<b256, StorageString> = StorageMap {},
l1_names: StorageMap<b256, StorageString> = StorageMap {},
decimals: StorageMap<b256, u8> = StorageMap {},
total_assets: u64 = 0,
}

Expand Down Expand Up @@ -203,8 +203,8 @@ impl SRC20 for Contract {

#[storage(read)]
fn decimals(asset: AssetId) -> Option<u8> {
match storage.tokens_minted.get(asset).try_read() {
Some(_) => Some(DECIMALS.try_as_u8().unwrap_or(DEFAULT_DECIMALS)),
match storage.l1_addresses.get(asset).try_read() {
Some(l1_address) => storage.decimals.get(l1_address).try_read(),
None => None,
}
}
Expand Down Expand Up @@ -329,6 +329,15 @@ fn _process_deposit(message_data: DepositMessage, msg_idx: u64) {
storage
.l1_addresses
.insert(asset_id, message_data.token_address);
if message_data.decimals < FUEL_ASSET_DECIMALS {
storage
.decimals
.insert(message_data.token_address, message_data.decimals);
} else {
storage
.decimals
.insert(message_data.token_address, FUEL_ASSET_DECIMALS);
}
};
// mint tokens & update storage
mint(sub_id, amount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,12 +512,13 @@ mod success {
}

#[tokio::test]
async fn register_metadata() {
async fn register_metadata_18_decimals() {
let mut wallet = create_wallet();
let configurables: Option<BridgeFungibleTokenContractConfigurables> = None;

let name = "Token".to_string();
let symbol = "TKN".to_string();
let decimals = 18;

let amount: u64 = u64::MAX;
let (deposit_message, coin, _) = create_deposit_message(
Expand All @@ -526,7 +527,232 @@ mod success {
FROM,
*wallet.address().hash(),
U256::from(amount),
BRIDGED_TOKEN_DECIMALS,
decimals,
configurables.clone(),
false,
None,
)
.await;

let metadata_message = create_metadata_message(
BRIDGED_TOKEN,
BRIDGED_TOKEN_ID,
&name,
&symbol,
configurables.clone(),
)
.await;

let (bridge, utxo_inputs) = setup_environment(
&mut wallet,
vec![coin],
vec![deposit_message, (0, metadata_message)],
None,
None,
configurables,
)
.await;

let asset_id = get_asset_id(bridge.contract_id(), BRIDGED_TOKEN);
let provider = wallet.provider().expect("Needs provider");

// Relay the deposit message
let tx_id = relay_message_to_contract(
&wallet,
utxo_inputs.message[0].clone(),
utxo_inputs.contract.clone(),
)
.await;
let tx_status = provider.tx_status(&tx_id).await.unwrap();
assert!(matches!(tx_status, TxStatus::Success { .. }));

let l1_address: Bits256 = bridge
.methods()
.asset_to_l1_address(asset_id)
.call()
.await
.unwrap()
.value;
assert_eq!(l1_address, Bits256::from_hex_str(BRIDGED_TOKEN).unwrap());

let l2_decimals: u8 = bridge
.methods()
.decimals(asset_id)
.call()
.await
.unwrap()
.value
.unwrap();

assert_eq!(l2_decimals, PROXY_TOKEN_DECIMALS as u8);

// Relay the metadata message
let tx_id = relay_message_to_contract(
&wallet,
utxo_inputs.message[1].clone(),
utxo_inputs.contract.clone(),
)
.await;

let tx_status = provider.tx_status(&tx_id).await.unwrap();
let receipts = tx_status.clone().take_receipts();
assert!(matches!(tx_status, TxStatus::Success { .. }));

let metadata_events = bridge
.log_decoder()
.decode_logs_with_type::<MetadataEvent>(&receipts)
.unwrap();

assert_eq!(metadata_events.len(), 1);
assert_eq!(
metadata_events[0].token_address,
Bits256::from_hex_str(BRIDGED_TOKEN).unwrap()
);

let registered_name = bridge.methods().name(asset_id).call().await.unwrap().value;

assert_eq!(name, registered_name.unwrap());

let registered_symbol = bridge
.methods()
.symbol(asset_id)
.call()
.await
.unwrap()
.value;

assert_eq!(symbol, registered_symbol.unwrap());
}

#[tokio::test]
async fn register_metadata_9_decimals() {
let mut wallet = create_wallet();
let configurables: Option<BridgeFungibleTokenContractConfigurables> = None;

let name = "Token".to_string();
let symbol = "TKN".to_string();
let decimals = 9;

let amount: u64 = u64::MAX;
let (deposit_message, coin, _) = create_deposit_message(
BRIDGED_TOKEN,
BRIDGED_TOKEN_ID,
FROM,
*wallet.address().hash(),
U256::from(amount),
decimals,
configurables.clone(),
false,
None,
)
.await;

let metadata_message = create_metadata_message(
BRIDGED_TOKEN,
BRIDGED_TOKEN_ID,
&name,
&symbol,
configurables.clone(),
)
.await;

let (bridge, utxo_inputs) = setup_environment(
&mut wallet,
vec![coin],
vec![deposit_message, (0, metadata_message)],
None,
None,
configurables,
)
.await;

let asset_id = get_asset_id(bridge.contract_id(), BRIDGED_TOKEN);
let provider = wallet.provider().expect("Needs provider");

// Relay the deposit message
let tx_id = relay_message_to_contract(
&wallet,
utxo_inputs.message[0].clone(),
utxo_inputs.contract.clone(),
)
.await;
let tx_status = provider.tx_status(&tx_id).await.unwrap();
assert!(matches!(tx_status, TxStatus::Success { .. }));

let l1_address: Bits256 = bridge
.methods()
.asset_to_l1_address(asset_id)
.call()
.await
.unwrap()
.value;
assert_eq!(l1_address, Bits256::from_hex_str(BRIDGED_TOKEN).unwrap());

let l2_decimals: u8 = bridge
.methods()
.decimals(asset_id)
.call()
.await
.unwrap()
.value
.unwrap();

assert_eq!(l2_decimals, PROXY_TOKEN_DECIMALS as u8);

// Relay the metadata message
let tx_id = relay_message_to_contract(
&wallet,
utxo_inputs.message[1].clone(),
utxo_inputs.contract.clone(),
)
.await;

let tx_status = provider.tx_status(&tx_id).await.unwrap();
let receipts = tx_status.clone().take_receipts();
assert!(matches!(tx_status, TxStatus::Success { .. }));

let metadata_events = bridge
.log_decoder()
.decode_logs_with_type::<MetadataEvent>(&receipts)
.unwrap();

assert_eq!(metadata_events.len(), 1);
assert_eq!(
metadata_events[0].token_address,
Bits256::from_hex_str(BRIDGED_TOKEN).unwrap()
);

let registered_name = bridge.methods().name(asset_id).call().await.unwrap().value;
assert_eq!(name, registered_name.unwrap());

let registered_symbol = bridge
.methods()
.symbol(asset_id)
.call()
.await
.unwrap()
.value;

assert_eq!(symbol, registered_symbol.unwrap());
}

#[tokio::test]
async fn register_metadata_6_decimals() {
let mut wallet = create_wallet();
let configurables: Option<BridgeFungibleTokenContractConfigurables> = None;

let name = "Token".to_string();
let symbol = "TKN".to_string();
let decimals = 6;

let amount: u64 = u64::MAX;
let (deposit_message, coin, _) = create_deposit_message(
BRIDGED_TOKEN,
BRIDGED_TOKEN_ID,
FROM,
*wallet.address().hash(),
U256::from(amount),
decimals,
configurables.clone(),
false,
None,
Expand Down Expand Up @@ -574,6 +800,16 @@ mod success {
.value;
assert_eq!(l1_address, Bits256::from_hex_str(BRIDGED_TOKEN).unwrap());

let l2_decimals: u8 = bridge
.methods()
.decimals(asset_id)
.call()
.await
.unwrap()
.value
.unwrap();
assert_eq!(l2_decimals, decimals as u8);

// Relay the metadata message
let tx_id = relay_message_to_contract(
&wallet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ contract FuelERC20GatewayV4 is
uint256(0), // token_id = 0 for all erc20 deposits
bytes32(uint256(uint160(msg.sender))),
to,
l2MintedAmount
l2MintedAmount,
uint256(decimals)
);
_deposit(tokenAddress, amount, l2MintedAmount, depositMessage);
}
Expand Down Expand Up @@ -181,6 +182,7 @@ contract FuelERC20GatewayV4 is
bytes32(uint256(uint160(msg.sender))),
to,
l2MintedAmount,
uint256(decimals),
data
);
_deposit(tokenAddress, amount, l2MintedAmount, depositMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const MessagePayloadSolidityTypes = [
'uint256', // depositor EVM address, padded
'uint256', // recipient FuelVM address
'uint256', // l2 amount to be minted
'uint256', // decimals
];

export function behavesLikeErc20GatewayV4(fixture: () => Promise<Env>) {
Expand Down Expand Up @@ -382,6 +383,7 @@ export function behavesLikeErc20GatewayV4(fixture: () => Promise<Env>) {
zeroPadValue(await user.getAddress(), 32),
depositTo,
depositAmount,
decimals,
]);
await expect(tx)
.to.emit(fuelMessagePortal, 'SendMessageCalled')
Expand Down Expand Up @@ -562,6 +564,7 @@ export function behavesLikeErc20GatewayV4(fixture: () => Promise<Env>) {
zeroPadValue(await user.getAddress(), 32),
depositTo,
depositAmount,
decimals,
]);
await expect(tx)
.to.emit(fuelMessagePortal, 'SendMessageCalled')
Expand Down Expand Up @@ -763,6 +766,7 @@ export function behavesLikeErc20GatewayV4(fixture: () => Promise<Env>) {
zeroPadValue(await user.getAddress(), 32),
depositTo,
downscaledDepositAmount,
DECIMALS,
]);
await expect(tx)
.to.emit(fuelMessagePortal, 'SendMessageCalled')
Expand Down
Loading