Tokens pallet (#243)

* Use Monero-compatible additional TX keys

This still sends a fingerprinting flare up if you send to a subaddress which
needs to be fixed. Despite that, Monero no should no longer fail to scan TXs
from monero-serai regarding additional keys.

Previously it failed becuase we supplied one key as THE key, and n-1 as
additional. Monero expects n for additional.

This does correctly select when to use THE key versus when to use the additional
key when sending. That removes the ability for recipients to fingerprint
monero-serai by receiving to a standard address yet needing to use an additional
key.

* Add tokens_primitives

Moves OutInstruction from in-instructions.

Turns Destination into OutInstruction.

* Correct in-instructions DispatchClass

* Add initial tokens pallet

* Don't allow pallet addresses to equal identity

* Add support for InInstruction::transfer

Requires a cargo update due to modifications made to serai-dex/substrate.

Successfully mints a token to a SeraiAddress.

* Bind InInstructions to an amount

* Add a call filter to the runtime

Prevents worrying about calls to the assets pallet/generally tightens things
up.

* Restore Destination

It was meged into OutInstruction, yet it didn't make sense for OutInstruction
to contain a SeraiAddress.

Also deletes the excessively dated Scenarios doc.

* Split PublicKey/SeraiAddress

Lets us define a custom Display/ToString for SeraiAddress.

Also resolves an oddity where PublicKey would be encoded as String, not
[u8; 32].

* Test burning tokens/retrieving OutInstructions

Modularizes processor_coinUpdates into a shared testing utility.

* Misc lint

* Don't use PolkadotExtrinsicParams
This commit is contained in:
Luke Parker
2023-01-28 01:47:13 -05:00
committed by GitHub
parent f12cc2cca6
commit 2ace339975
39 changed files with 1213 additions and 594 deletions

View File

@@ -0,0 +1,38 @@
[package]
name = "tokens-pallet"
version = "0.1.0"
description = "Mint and burn Serai tokens"
license = "AGPL-3.0-only"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021"
publish = false
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-assets = { git = "https://github.com/serai-dex/substrate", default-features = false }
serai-primitives = { path = "../../serai/primitives", default-features = false }
tokens-primitives = { path = "../primitives", default-features = false }
[features]
std = [
"scale/std",
"scale-info/std",
"frame-system/std",
"frame-support/std",
"pallet-assets/std",
"serai-primitives/std",
]
default = ["std"]

View File

@@ -0,0 +1,15 @@
AGPL-3.0-only license
Copyright (c) 2023 Luke Parker
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License Version 3 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -0,0 +1,83 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
pub use tokens_primitives as primitives;
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::{pallet_prelude::*, RawOrigin};
use pallet_assets::{Config as AssetsConfig, Pallet as AssetsPallet};
use serai_primitives::{SubstrateAmount, Coin, Balance, PublicKey, SeraiAddress, AccountLookup};
use primitives::{ADDRESS, OutInstruction};
use super::*;
#[pallet::config]
pub trait Config:
frame_system::Config<AccountId = PublicKey, Lookup = AccountLookup>
+ AssetsConfig<AssetIdParameter = Coin, Balance = SubstrateAmount>
{
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
// Mint is technically redundant as the assets pallet has the exact same event already
// Providing our own definition here just helps consolidate code
Mint { address: SeraiAddress, balance: Balance },
Burn { address: SeraiAddress, balance: Balance, instruction: OutInstruction },
}
#[pallet::pallet]
#[pallet::generate_store(pub(crate) trait Store)]
pub struct Pallet<T>(PhantomData<T>);
impl<T: Config> Pallet<T> {
fn burn_internal(
address: SeraiAddress,
balance: Balance,
instruction: OutInstruction,
) -> DispatchResult {
AssetsPallet::<T>::burn(
RawOrigin::Signed(ADDRESS.into()).into(),
balance.coin,
address,
balance.amount.0,
)?;
Pallet::<T>::deposit_event(Event::Burn { address, balance, instruction });
Ok(())
}
pub fn mint(address: SeraiAddress, balance: Balance) {
// TODO: Prevent minting when it'd cause an amount exceeding the bond
AssetsPallet::<T>::mint(
RawOrigin::Signed(ADDRESS.into()).into(),
balance.coin,
address,
balance.amount.0,
)
.unwrap();
Pallet::<T>::deposit_event(Event::Mint { address, balance });
}
}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight((0, DispatchClass::Normal))] // TODO
pub fn burn(
origin: OriginFor<T>,
balance: Balance,
instruction: OutInstruction,
) -> DispatchResult {
Self::burn_internal(ensure_signed(origin)?.into(), balance, instruction)
}
}
}
pub use pallet::*;