Skip to main content

linera_sdk/abis/
wrapped_fungible.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! An ABI for applications that implement a wrapped (bridged) fungible token with Mint/Burn.
5
6use std::collections::BTreeMap;
7
8use async_graphql::{Request, Response};
9pub use linera_base::identifiers::Account;
10use linera_base::{
11    abi::{ContractAbi, ServiceAbi},
12    data_types::U128,
13    identifiers::{AccountOwner, ApplicationId, ChainId},
14};
15use linera_sdk_derive::{GraphQLMutationRootInCrate, StableEnumInCrate};
16use serde::{Deserialize, Serialize};
17
18/// Parameters for a wrapped fungible token backed by an EVM bridge.
19#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
20pub struct WrappedParameters {
21    /// Ticker symbol (e.g. "USDC")
22    pub ticker_symbol: String,
23    /// Number of decimal places used by the source ERC-20 (e.g. 6 for USDC).
24    pub decimals: u8,
25    /// The chain on which minting and burning are allowed (the bridge chain).
26    pub mint_chain_id: ChainId,
27    /// The ERC-20 token address on the source EVM chain
28    pub evm_token_address: [u8; 20],
29    /// The EVM chain ID of the source chain (e.g. 8453 for Base)
30    pub evm_source_chain_id: u64,
31}
32
33/// Event emitted by the bridge application on its "burns" stream when it burns
34/// wrapped tokens on the bridge chain. The relayer observes these and forwards
35/// them to EVM to release the corresponding ERC-20 tokens.
36#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
37pub struct BurnEvent {
38    /// The Ethereum address to receive the unlocked ERC-20 tokens
39    pub target: [u8; 20],
40    /// Amount of tokens burned, in raw sub-units of the source ERC-20.
41    pub amount: U128,
42}
43
44/// Initial accounts and balances for the wrapped fungible token application.
45#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
46#[allow(missing_docs)]
47pub struct InitialState {
48    pub accounts: BTreeMap<AccountOwner, U128>,
49}
50
51/// Builder for [`InitialState`].
52#[derive(Debug, Default)]
53pub struct InitialStateBuilder {
54    account_balances: BTreeMap<AccountOwner, U128>,
55}
56
57impl InitialStateBuilder {
58    /// Adds an account with the given initial balance.
59    pub fn with_account(mut self, account: AccountOwner, balance: U128) -> Self {
60        self.account_balances.insert(account, balance);
61        self
62    }
63
64    /// Builds the [`InitialState`] from the configured accounts.
65    pub fn build(&self) -> InitialState {
66        InitialState {
67            accounts: self.account_balances.clone(),
68        }
69    }
70}
71
72/// Response variants returned by the wrapped fungible token application.
73#[derive(Debug, StableEnumInCrate, Default)]
74#[allow(missing_docs)]
75pub enum FungibleResponse {
76    #[default]
77    Ok,
78    Balance(U128),
79    TickerSymbol(String),
80}
81
82/// Operations for the wrapped fungible token application.
83#[derive(Debug, StableEnumInCrate, GraphQLMutationRootInCrate)]
84#[allow(missing_docs)]
85pub enum WrappedFungibleOperation {
86    /// Requests an account balance.
87    Balance { owner: AccountOwner },
88    /// Requests this fungible token's ticker symbol.
89    TickerSymbol,
90    /// Approve the transfer of tokens.
91    Approve {
92        owner: AccountOwner,
93        spender: AccountOwner,
94        allowance: U128,
95    },
96    /// Transfers tokens from a (locally owned) account to a (possibly remote) account.
97    Transfer {
98        owner: AccountOwner,
99        amount: U128,
100        target_account: Account,
101    },
102    /// Transfers tokens from a (locally owned) account using a previously approved allowance.
103    TransferFrom {
104        owner: AccountOwner,
105        spender: AccountOwner,
106        amount: U128,
107        target_account: Account,
108    },
109    /// Same as `Transfer` but the source account may be remote.
110    Claim {
111        source_account: Account,
112        amount: U128,
113        target_account: Account,
114    },
115    /// Mints new tokens and transfers them to a target account. Driven by the
116    /// registered authorized caller (see [`Self::RegisterAuthorizedCaller`]) on the
117    /// designated mint chain.
118    MintAndTransfer {
119        target_account: Account,
120        amount: U128,
121    },
122    /// Burns tokens from an account. Authorized only via the registered authorized
123    /// caller (see [`Self::RegisterAuthorizedCaller`]) on the designated mint chain.
124    Burn { owner: AccountOwner, amount: U128 },
125    /// Registers the application authorized to drive `MintAndTransfer`/`Burn`. Must run on
126    /// the designated `mint_chain_id` — the only chain where it is consulted — and
127    /// requires an authenticated signer. Because an authorized caller may take
128    /// this token's id as a creation parameter, the two cannot reference each
129    /// other at creation; this token is created first and registers its caller
130    /// afterwards.
131    RegisterAuthorizedCaller { app_id: ApplicationId },
132}
133
134/// Cross-chain message used by the wrapped fungible token application.
135/// Amounts are [`U128`] in the source ERC-20's decimal scale.
136#[derive(Debug, Deserialize, Serialize)]
137#[allow(missing_docs)]
138pub enum Message {
139    /// Credits the given `target` account, unless the message is bouncing, in which case
140    /// `source` is credited instead.
141    Credit {
142        target: AccountOwner,
143        amount: U128,
144        source: AccountOwner,
145    },
146
147    /// Withdraws from the given account and starts a transfer to the target account.
148    Withdraw {
149        owner: AccountOwner,
150        amount: U128,
151        target_account: Account,
152    },
153}
154
155/// ABI for the wrapped fungible token application.
156pub struct WrappedFungibleTokenAbi;
157
158impl ContractAbi for WrappedFungibleTokenAbi {
159    type Operation = WrappedFungibleOperation;
160    type Response = FungibleResponse;
161}
162
163impl ServiceAbi for WrappedFungibleTokenAbi {
164    type Query = Request;
165    type QueryResponse = Response;
166}