pallet-stablecoin = '0.0.6'
Note: Not published to crates.io
This is a substrate pallet showcasing a sample implementation of a non-collateralized stablecoin based on the Basis Whitepaper.
Note: Example project for illustration, NOT audited and NOT production ready.
This pallet depends on an external implementation of its FetchPrice
trait - for example by an offchain worker - to act as a price oracle.
To add this pallet to your runtime, simply include the following in your runtime's Cargo.toml
file:
[dependencies.pallet-stablecoin]
default_features = false
git = 'https://github.com/apopiak/pallet-stablecoin.git'
and update your runtime's std
feature to include this pallet's std
feature:
std = [
# --snip--
'pallet_stablecoin/std',
]
Here is an example imlementation of its trait:
use pallet_stablecoin::Coins;
parameter_types! {
pub const ExpirationPeriod: BlockNumber = 5 * 365 * DAYS; // 5 years = 5 * 365 * DAYS
pub const MaximumBids: usize = 1_000;
pub const MinimumBondPrice: Perbill = Perbill::from_percent(10);
pub const AdjustmentFrequency: BlockNumber = 1 * MINUTES; // 1 minute = 60000 / MILLISECS_PER_BLOCK
pub const BaseUnit: Coins = 1_000_000;
pub const InitialSupply: Coins = 1000 * BaseUnit::get();
pub const MinimumSupply: Coins = BaseUnit::get();
}
impl pallet_stablecoin::Trait for Runtime {
type Event = Event;
type CoinPrice = some_price_oracle::Module<Runtime>;
type ExpirationPeriod = ExpirationPeriod;
type MaximumBids = MaximumBids;
type MinimumBondPrice = MinimumBondPrice;
type AdjustmentFrequency = AdjustmentFrequency;
type BaseUnit = BaseUnit;
type InitialSupply = InitialSupply;
type MinimumSupply = MinimumSupply;
}
and include it in your construct_runtime!
macro:
Stablecoin: pallet_stablecoin::{Module, Call, Storage, Event<T>},
Runtimes using the pallet need to add the StablecoinConfig
to their genesis config.
The config expects a Vec(AccountId, u64)
to initialize the shareholders.
See the following snippet for an example:
use node_template_runtime::{ // ... other imports
StablecoinConfig
};
// ...
GenesisConfig {
system: Some(SystemConfig { /* elided */ }),
// ... other configs
stablecoin: Some(StablecoinConfig {
shareholders: endowed_accounts.iter().cloned().map(|acc| (acc, 1)).collect(),
}),
}
With this config the endowed accounts will be the shareholders of the stablecoin.
The implementation follows the Basis Whitepaper. (It also takes some inspiration from this unfinished Solidity implementation.)
Basis
tokens are calledCoins
and represent an ERC20-like token that will be stabilized by increasing and decreasing supply.Bond tokens
are calledBonds
and allow in- and decreasing the supply. They represent a promise for nCoins
in the future (under certain conditions).Share tokens
are calledShares
and have a supply fixed at initialization time of the stablecoin. If there are not enoughBonds
to increase coin supply,Coins
are distributed to the accounts holding shares.
The ExpirationPeriod
is configurable and measured in blocks (type BlockNumber
).
The continuous bidding auction for bonds is implemented as a bounded priority queue to reduce storage costs. The paper does not specify whether it should or should not be bounded.
You can view the reference docs for this pallet by running:
cargo doc --open