mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Coins pallet (#399)
* initial implementation * add function to get a balance of an account * add support for multiple coins * rename pallet to "coins-pallet" * replace balances, assets and tokens pallet with coins pallet in runtime * add total supply info * update client side for new Coins pallet * handle fees * bug fixes * Update FeeAccount test * Fmt * fix pr comments * remove extraneous Imbalance type * Minor tweaks --------- Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
This commit is contained in:
@@ -15,7 +15,7 @@ mod other_primitives {
|
||||
pub use serai_runtime::in_instructions::primitives;
|
||||
}
|
||||
pub mod coins {
|
||||
pub use serai_runtime::tokens::primitives;
|
||||
pub use serai_runtime::coins::primitives;
|
||||
}
|
||||
pub mod validator_sets {
|
||||
pub use serai_runtime::validator_sets::primitives;
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
use sp_core::sr25519::Public;
|
||||
use serai_runtime::{
|
||||
primitives::{SeraiAddress, SubstrateAmount, Amount, Coin, Balance},
|
||||
assets::{AssetDetails, AssetAccount},
|
||||
tokens, Tokens, Runtime,
|
||||
coins, Coins, Runtime,
|
||||
};
|
||||
pub use tokens::primitives;
|
||||
use primitives::OutInstruction;
|
||||
pub use coins::primitives;
|
||||
use primitives::OutInstructionWithBalance;
|
||||
|
||||
use subxt::tx::Payload;
|
||||
|
||||
use crate::{TemporalSerai, SeraiError, Composite, scale_value, scale_composite};
|
||||
|
||||
const PALLET: &str = "Tokens";
|
||||
const PALLET: &str = "Coins";
|
||||
|
||||
pub type TokensEvent = tokens::Event<Runtime>;
|
||||
pub type CoinsEvent = coins::Event<Runtime>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiCoins<'a>(pub(crate) TemporalSerai<'a>);
|
||||
@@ -22,37 +20,25 @@ impl<'a> SeraiCoins<'a> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub async fn mint_events(&self) -> Result<Vec<TokensEvent>, SeraiError> {
|
||||
self.0.events::<Tokens, _>(|event| matches!(event, TokensEvent::Mint { .. })).await
|
||||
pub async fn mint_events(&self) -> Result<Vec<CoinsEvent>, SeraiError> {
|
||||
self.0.events::<Coins, _>(|event| matches!(event, CoinsEvent::Mint { .. })).await
|
||||
}
|
||||
|
||||
pub async fn burn_events(&self) -> Result<Vec<TokensEvent>, SeraiError> {
|
||||
self.0.events::<Tokens, _>(|event| matches!(event, TokensEvent::Burn { .. })).await
|
||||
pub async fn burn_events(&self) -> Result<Vec<CoinsEvent>, SeraiError> {
|
||||
self.0.events::<Coins, _>(|event| matches!(event, CoinsEvent::Burn { .. })).await
|
||||
}
|
||||
|
||||
pub async fn sri_balance(&self, address: SeraiAddress) -> Result<u64, SeraiError> {
|
||||
let data: Option<
|
||||
serai_runtime::system::AccountInfo<u32, serai_runtime::balances::AccountData<u64>>,
|
||||
> = self.0.storage("System", "Account", Some(vec![scale_value(address)])).await?;
|
||||
Ok(data.map(|data| data.data.free).unwrap_or(0))
|
||||
}
|
||||
|
||||
pub async fn token_supply(&self, coin: Coin) -> Result<Amount, SeraiError> {
|
||||
pub async fn coin_supply(&self, coin: Coin) -> Result<Amount, SeraiError> {
|
||||
Ok(Amount(
|
||||
self
|
||||
.0
|
||||
.storage::<AssetDetails<SubstrateAmount, SeraiAddress, SubstrateAmount>>(
|
||||
"Assets",
|
||||
"Asset",
|
||||
Some(vec![scale_value(coin)]),
|
||||
)
|
||||
.storage::<SubstrateAmount>(PALLET, "Supply", Some(vec![scale_value(coin)]))
|
||||
.await?
|
||||
.map(|token| token.supply)
|
||||
.unwrap_or(0),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn token_balance(
|
||||
pub async fn coin_balance(
|
||||
&self,
|
||||
coin: Coin,
|
||||
address: SeraiAddress,
|
||||
@@ -60,35 +46,25 @@ impl<'a> SeraiCoins<'a> {
|
||||
Ok(Amount(
|
||||
self
|
||||
.0
|
||||
.storage::<AssetAccount<SubstrateAmount, SubstrateAmount, (), Public>>(
|
||||
"Assets",
|
||||
"Account",
|
||||
Some(vec![scale_value(coin), scale_value(address)]),
|
||||
.storage::<SubstrateAmount>(
|
||||
PALLET,
|
||||
"Balances",
|
||||
Some(vec![scale_value(address), scale_value(coin)]),
|
||||
)
|
||||
.await?
|
||||
.map(|account| account.balance())
|
||||
.unwrap_or(0),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn transfer_sri(to: SeraiAddress, amount: Amount) -> Payload<Composite<()>> {
|
||||
pub fn transfer(to: SeraiAddress, balance: Balance) -> Payload<Composite<()>> {
|
||||
Payload::new(
|
||||
"Balances",
|
||||
// TODO: Use transfer_allow_death?
|
||||
// TODO: Replace the Balances pallet with something much simpler
|
||||
PALLET,
|
||||
"transfer",
|
||||
scale_composite(serai_runtime::balances::Call::<Runtime>::transfer {
|
||||
dest: to,
|
||||
value: amount.0,
|
||||
}),
|
||||
scale_composite(serai_runtime::coins::Call::<Runtime>::transfer { to, balance }),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn burn(balance: Balance, instruction: OutInstruction) -> Payload<Composite<()>> {
|
||||
Payload::new(
|
||||
PALLET,
|
||||
"burn",
|
||||
scale_composite(tokens::Call::<Runtime>::burn { balance, instruction }),
|
||||
)
|
||||
pub fn burn(instruction: OutInstructionWithBalance) -> Payload<Composite<()>> {
|
||||
Payload::new(PALLET, "burn", scale_composite(coins::Call::<Runtime>::burn { instruction }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use serai_client::{
|
||||
primitives::{InInstruction, InInstructionWithBalance, Batch},
|
||||
InInstructionsEvent,
|
||||
},
|
||||
coins::TokensEvent,
|
||||
coins::CoinsEvent,
|
||||
Serai,
|
||||
};
|
||||
|
||||
@@ -65,8 +65,8 @@ serai_test!(
|
||||
}
|
||||
|
||||
let serai = serai.coins();
|
||||
assert_eq!(serai.mint_events().await.unwrap(), vec![TokensEvent::Mint { address, balance }],);
|
||||
assert_eq!(serai.token_supply(coin).await.unwrap(), amount);
|
||||
assert_eq!(serai.token_balance(coin, address).await.unwrap(), amount);
|
||||
assert_eq!(serai.mint_events().await.unwrap(), vec![CoinsEvent::Mint { address, balance }],);
|
||||
assert_eq!(serai.coin_supply(coin).await.unwrap(), amount);
|
||||
assert_eq!(serai.coin_balance(coin, address).await.unwrap(), amount);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ use blake2::{
|
||||
|
||||
use scale::Encode;
|
||||
|
||||
use serai_runtime::coins::primitives::OutInstructionWithBalance;
|
||||
use sp_core::Pair;
|
||||
|
||||
use serai_client::{
|
||||
@@ -19,7 +20,7 @@ use serai_client::{
|
||||
InInstructionsEvent,
|
||||
primitives::{InInstruction, InInstructionWithBalance, Batch},
|
||||
},
|
||||
coins::{primitives::OutInstruction, TokensEvent},
|
||||
coins::{primitives::OutInstruction, CoinsEvent},
|
||||
PairSigner, Serai, SeraiCoins,
|
||||
};
|
||||
|
||||
@@ -69,10 +70,10 @@ serai_test!(
|
||||
|
||||
assert_eq!(
|
||||
serai.coins().mint_events().await.unwrap(),
|
||||
vec![TokensEvent::Mint { address, balance }]
|
||||
vec![CoinsEvent::Mint { address, balance }]
|
||||
);
|
||||
assert_eq!(serai.coins().token_supply(coin).await.unwrap(), amount);
|
||||
assert_eq!(serai.coins().token_balance(coin, address).await.unwrap(), amount);
|
||||
assert_eq!(serai.coins().coin_supply(coin).await.unwrap(), amount);
|
||||
assert_eq!(serai.coins().coin_balance(coin, address).await.unwrap(), amount);
|
||||
|
||||
// Now burn it
|
||||
let mut rand_bytes = vec![0; 32];
|
||||
@@ -83,13 +84,16 @@ serai_test!(
|
||||
OsRng.fill_bytes(&mut rand_bytes);
|
||||
let data = Data::new(rand_bytes).unwrap();
|
||||
|
||||
let out = OutInstruction { address: external_address, data: Some(data) };
|
||||
let instruction = OutInstructionWithBalance {
|
||||
balance,
|
||||
instruction: OutInstruction { address: external_address, data: Some(data) },
|
||||
};
|
||||
let serai = serai.into_inner();
|
||||
let block = publish_tx(
|
||||
&serai
|
||||
.sign(
|
||||
&PairSigner::new(pair),
|
||||
&SeraiCoins::burn(balance, out.clone()),
|
||||
&SeraiCoins::burn(instruction.clone()),
|
||||
0,
|
||||
BaseExtrinsicParamsBuilder::new(),
|
||||
)
|
||||
@@ -99,8 +103,8 @@ serai_test!(
|
||||
|
||||
let serai = serai.as_of(block).coins();
|
||||
let events = serai.burn_events().await.unwrap();
|
||||
assert_eq!(events, vec![TokensEvent::Burn { address, balance, instruction: out }]);
|
||||
assert_eq!(serai.token_supply(coin).await.unwrap(), Amount(0));
|
||||
assert_eq!(serai.token_balance(coin, address).await.unwrap(), Amount(0));
|
||||
assert_eq!(events, vec![CoinsEvent::Burn { address, instruction }]);
|
||||
assert_eq!(serai.coin_supply(coin).await.unwrap(), Amount(0));
|
||||
assert_eq!(serai.coin_balance(coin, address).await.unwrap(), Amount(0));
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user