Skip to content

Commit

Permalink
Replace FRC20 with SRC20 (#102)
Browse files Browse the repository at this point in the history
Co-authored-by: K1-R1 <[email protected]>
Co-authored-by: Cameron Carstens <[email protected]>
Co-authored-by: Braqzen <[email protected]>
  • Loading branch information
4 people authored Nov 20, 2023
1 parent e8ef9e5 commit c54a1be
Show file tree
Hide file tree
Showing 17 changed files with 521 additions and 176 deletions.
5 changes: 5 additions & 0 deletions .changeset/perfect-fishes-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fuel-bridge/fungible-token': minor
---

Replace FRC20 with SRC20
6 changes: 6 additions & 0 deletions Forc.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ source = "member"
dependencies = [
"contract_message_receiver",
"reentrancy",
"src_20",
"std",
]

Expand All @@ -29,6 +30,11 @@ name = "reentrancy"
source = "git+https://github.com/FuelLabs/sway-libs?tag=v0.12.0#063f118a3104adb6a04207ca877993b5ad03a492"
dependencies = ["std"]

[[package]]
name = "src_20"
source = "git+https://github.com/FuelLabs/sway-standards?tag=v0.1.2#a3744aa3dcb8c950a433d1fc16645ef9a83dc583"
dependencies = ["std"]

[[package]]
name = "std"
source = "git+https://github.com/fuellabs/sway?tag=v0.46.0#e75f14b03636bc96751a6760304a1a6d3eb5937d"
Expand Down
2 changes: 2 additions & 0 deletions packages/fungible-token/bridge-fungible-token/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ name = "bridge_fungible_token"
[dependencies]
contract_message_receiver = { path = "../../message-predicates/contract-message-receiver" }
reentrancy = { git = "https://github.com/FuelLabs/sway-libs", tag = "v0.12.0" }
src_20 = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.1.2" }

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
library;

pub mod frc20;
pub mod bridge;
pub mod src7;
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ abi Bridge {

// Recovers the sub_id used to generate an asset_id (= sha256(contract_id, sub_id))
#[storage(read)]
fn asset_to_sub_id(asset_id: b256) -> b256;
fn asset_to_sub_id(asset_id: AssetId) -> SubId;

/// Sends a message to the L1 gateway to inform of capabilities to receive funds
#[storage(read)]
Expand Down

This file was deleted.

87 changes: 58 additions & 29 deletions packages/fungible-token/bridge-fungible-token/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use contract_message_receiver::MessageReceiver;
use errors::BridgeFungibleTokenError;
use data_structures::{ADDRESS_DEPOSIT_DATA_LEN, CONTRACT_DEPOSIT_WITHOUT_DATA_LEN, MessageData};
use events::{ClaimRefundEvent, DepositEvent, RefundRegisteredEvent, WithdrawalEvent};
use interface::{bridge::Bridge, frc20::FRC20, src7::{Metadata, SRC7}};
use interface::{bridge::Bridge, src7::{Metadata, SRC7}};
use reentrancy::reentrancy_guard;
use std::{
call_frames::{
Expand All @@ -21,6 +21,10 @@ use std::{
},
constants::ZERO_B256,
context::msg_amount,
flags::{
disable_panic_on_overflow,
enable_panic_on_overflow,
},
hash::Hash,
hash::sha256,
inputs::input_message_sender,
Expand All @@ -39,6 +43,7 @@ use utils::{
encode_data,
encode_register_calldata,
};
use src_20::SRC20;

configurable {
DECIMALS: u8 = 9u8,
Expand All @@ -50,9 +55,10 @@ configurable {
}

storage {
asset_to_sub_id: StorageMap<AssetId, b256> = StorageMap {},
asset_to_sub_id: StorageMap<AssetId, SubId> = StorageMap {},
refund_amounts: StorageMap<b256, StorageMap<b256, b256>> = StorageMap {},
tokens_minted: u64 = 0,
tokens_minted: StorageMap<AssetId, u64> = StorageMap {},
total_assets: u64 = 0,
}

// Implement the process_message function required to be a message receiver
Expand All @@ -69,14 +75,6 @@ impl MessageReceiver for Contract {
let message_data = MessageData::parse(msg_idx);
require(message_data.amount != ZERO_B256, BridgeFungibleTokenError::NoCoinsSent);

let sub_id = message_data.token_id;
let asset_id = AssetId::from(sha256((contract_id(), sub_id)));

if storage.asset_to_sub_id.get(asset_id).try_read().is_none()
{
storage.asset_to_sub_id.insert(asset_id, sub_id);
};

// register a refund if tokens don't match
if (message_data.token_address != BRIDGED_TOKEN) {
register_refund(message_data.from, message_data.token_address, message_data.token_id, message_data.amount);
Expand All @@ -91,12 +89,31 @@ impl MessageReceiver for Contract {
register_refund(message_data.from, message_data.token_address, message_data.token_id, message_data.amount);
},
Result::Ok(amount) => {
let sub_id = message_data.token_id;
let asset_id = AssetId::new(contract_id(), sub_id);

disable_panic_on_overflow();

let current_total_supply = storage.tokens_minted.get(asset_id).try_read().unwrap_or(0);
let new_total_supply = current_total_supply + amount;

if new_total_supply < current_total_supply {
register_refund(message_data.from, message_data.token_address, message_data.token_id, message_data.amount);
return;
}

enable_panic_on_overflow();

storage.tokens_minted.insert(asset_id, new_total_supply);

if storage.asset_to_sub_id.get(asset_id).try_read().is_none()
{
storage.asset_to_sub_id.insert(asset_id, sub_id);
storage.total_assets.write(storage.total_assets.try_read().unwrap_or(0) + 1);
};

// mint tokens & update storage
mint(sub_id, amount);
match storage.tokens_minted.try_read() {
Option::Some(value) => storage.tokens_minted.write(value + amount),
Option::None => storage.tokens_minted.write(amount),
};

// when depositing to an address, msg_data.len is ADDRESS_DEPOSIT_DATA_LEN bytes.
// when depositing to a contract, msg_data.len is CONTRACT_DEPOSIT_WITHOUT_DATA_LEN bytes.
Expand Down Expand Up @@ -166,7 +183,7 @@ impl Bridge for Contract {

// attempt to adjust amount into base layer decimals and burn the sent tokens
let adjusted_amount = adjust_withdrawal_decimals(amount, DECIMALS, BRIDGED_TOKEN_DECIMALS).unwrap();
storage.tokens_minted.write(storage.tokens_minted.read() - amount);
storage.tokens_minted.insert(asset_id, storage.tokens_minted.get(asset_id).read() - amount);
burn(sub_id, amount);

// send a message to unlock this amount on the base layer gateway contract
Expand All @@ -192,32 +209,44 @@ impl Bridge for Contract {
}

#[storage(read)]
fn asset_to_sub_id(asset_id: b256) -> b256 {
_asset_to_sub_id(AssetId::from(asset_id))
fn asset_to_sub_id(asset_id: AssetId) -> SubId {
_asset_to_sub_id(asset_id)
}
}

impl FRC20 for Contract {
impl SRC20 for Contract {
#[storage(read)]
fn total_supply() -> U256 {
let minted: u64 = storage.tokens_minted.try_read().unwrap_or(0);
fn total_assets() -> u64 {
storage.total_assets.try_read().unwrap_or(0)
}

U256::from((0, 0, 0, minted))
#[storage(read)]
fn total_supply(asset: AssetId) -> Option<u64> {
storage.tokens_minted.get(asset).try_read()
}

#[storage(read)]
fn name() -> str[64] {
NAME
fn name(asset: AssetId) -> Option<String> {
match storage.tokens_minted.get(asset).try_read() {
Some(_) => Some(String::from_ascii_str(from_str_array(NAME))),
None => None,
}
}

#[storage(read)]
fn symbol() -> str[32] {
SYMBOL
fn symbol(asset: AssetId) -> Option<String> {
match storage.tokens_minted.get(asset).try_read() {
Some(_) => Some(String::from_ascii_str(from_str_array(SYMBOL))),
None => None,
}
}

#[storage(read)]
fn decimals() -> u8 {
DECIMALS
fn decimals(asset: AssetId) -> Option<u8> {
match storage.tokens_minted.get(asset).try_read() {
Some(_) => Some(DECIMALS),
None => None,
}
}
}

Expand Down Expand Up @@ -252,7 +281,7 @@ fn register_refund(
}

#[storage(read)]
fn _asset_to_sub_id(asset_id: AssetId) -> b256 {
fn _asset_to_sub_id(asset_id: AssetId) -> SubId {
let sub_id = storage.asset_to_sub_id.get(asset_id).try_read();
require(sub_id.is_some(), BridgeFungibleTokenError::AssetNotFound);
sub_id.unwrap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ mod success {

use super::*;

use crate::utils::setup::get_asset_id;
use crate::utils::{
constants::BRIDGED_TOKEN_GATEWAY,
interface::bridge::{
bridged_token, bridged_token_decimals, bridged_token_gateway, claim_refund,
interface::{
bridge::{bridged_token, bridged_token_decimals, bridged_token_gateway, claim_refund},
src20::total_supply,
},
setup::{ClaimRefundEvent, RefundRegisteredEvent},
setup::{get_asset_id, ClaimRefundEvent, RefundRegisteredEvent},
};
use fuels::{prelude::Address, programs::contract::SettableContract, tx::Receipt};
use std::str::FromStr;
Expand Down Expand Up @@ -80,7 +80,7 @@ mod success {
.unwrap();

let asset_balance =
contract_balance(provider, bridge.contract_id(), AssetId::default()).await;
contract_balance(&provider, bridge.contract_id(), AssetId::default()).await;
let balance = wallet_balance(&wallet, &get_asset_id(bridge.contract_id())).await;

// Verify the message value was received by the bridge contract
Expand Down Expand Up @@ -219,7 +219,7 @@ mod success {
.unwrap();

let asset_balance =
contract_balance(provider, bridge.contract_id(), AssetId::default()).await;
contract_balance(&provider, bridge.contract_id(), AssetId::default()).await;
let balance = wallet_balance(&wallet, &get_asset_id(bridge.contract_id())).await;

// Verify the message value was received by the bridge contract
Expand Down Expand Up @@ -343,21 +343,21 @@ mod success {
// Do nothing
}
_ => {
assert!(false, "Transaction did not succeed")
panic!("Transaction did not succeed")
}
}

let _receipts = tx_status.take_receipts();

let asset_balance =
contract_balance(provider, bridge.contract_id(), AssetId::default()).await;
contract_balance(&provider, bridge.contract_id(), AssetId::default()).await;
let balance = wallet_balance(&wallet, &get_asset_id(bridge.contract_id())).await;

let expected_deposited_amount = config.fuel_equivalent_amount(config.amount.max);

// Verify the message value was received by the bridge contract
assert_eq!(asset_balance, MESSAGE_AMOUNT);

// Check that wallet now has bridged coins
assert_eq!(balance, config.fuel_equivalent_amount(config.amount.max));
assert_eq!(balance, expected_deposited_amount);

// Now try to withdraw
let withdrawal_amount = config.fuel_equivalent_amount(config.amount.test);
Expand Down Expand Up @@ -392,6 +392,12 @@ mod success {
assert_eq!(token, Bits256::from_hex_str(BRIDGED_TOKEN).unwrap());
assert_eq!(token_id, Bits256::from_hex_str(BRIDGED_TOKEN_ID).unwrap());
assert_eq!(amount, config.amount.test);

// Check that supply has decreased by withdrawal_amount
let supply = total_supply(&bridge, get_asset_id(bridge.contract_id()))
.await
.unwrap();
assert_eq!(supply, expected_deposited_amount - withdrawal_amount);
}

#[tokio::test]
Expand Down Expand Up @@ -438,7 +444,7 @@ mod success {
.await;

let asset_balance =
contract_balance(provider, bridge.contract_id(), AssetId::default()).await;
contract_balance(&provider, bridge.contract_id(), AssetId::default()).await;
let balance = wallet_balance(&wallet, &get_asset_id(bridge.contract_id())).await;

// Verify the message value was received by the bridge contract
Expand Down Expand Up @@ -484,6 +490,12 @@ mod success {

// now verify that the initial amount == the final amount
assert_eq!(msg_data_amount, config.amount.min);

// Verify that total_supply is zero after withdrawing the funds
let supply = total_supply(&bridge, get_asset_id(bridge.contract_id()))
.await
.unwrap();
assert_eq!(supply, 0u64);
}

#[tokio::test]
Expand Down Expand Up @@ -521,6 +533,8 @@ mod success {
}

mod revert {
use std::str::FromStr;

use super::*;
use crate::utils::setup::get_asset_id;

Expand Down Expand Up @@ -571,7 +585,7 @@ mod revert {
.await;

let asset_balance =
contract_balance(provider, bridge.contract_id(), AssetId::default()).await;
contract_balance(&provider, bridge.contract_id(), AssetId::default()).await;
let balance = wallet_balance(&wallet, &get_asset_id(bridge.contract_id())).await;

// Verify the message value was received by the bridge contract
Expand Down Expand Up @@ -621,10 +635,10 @@ mod revert {
configurables,
)
.await;

bridge
.methods()
.asset_to_sub_id(Bits256::from_hex_str(incorrect_asset_id).unwrap())
.asset_to_sub_id(AssetId::from_str(incorrect_asset_id).unwrap())
.call()
.await
.unwrap();
Expand Down
Loading

0 comments on commit c54a1be

Please sign in to comment.