Module for tokenization of carbon units from the external registry. (Based on Parity Asset pallet )
The Carbon Assets module provides functionality for the tokenization of Carbon Units from the external registry. The current edition needs a manager who verifies the tokenization.
- Custodian: The Evercity manager. Only a custodian can mint created carbon asset. Can be set in Genesis Config or by Sudo
set_custodian
. - Carbon Asset burning: Burn of tokenized carbon asset. The owner receives Burn Certificate.
- BurnCertificate: The storage of amount of carbon assets burned per
AccountId
perAssetId
.
- It's necessary to setup custodian for minting assets. Use sudo
set_custodian
extrinsic to some address - Don't forget to replenish balances of addresses which will hold assets (even those where you're going to transfer to)
- User creates a carbon asset via
create
extrinsic. The user sets a name and a symbol of the asset. Asset decimals are set to 9.AssetId
is generated. - User goes to the external registry and buys and retires/transfers the asset with the generated
AssetId
(and maybe name too). The user receives some kind of public serial number of retirement. - User updates metadata of the asset via
set_project_data
extrinsic. The user should include the serial number from the previous step, and some project information and store that on ipfs. The metadata is updated withurl
and ipfs linkdata_ipfs
. - Custodian verifies all data via the link from the previous step and
mint
carbon assets to the user's account. - The user can burn carbon assets that they have (that is what carbon assets are made for) via
self_burn
extrinsic. Then user receives a BurnCertificate. The user can burn a particular carbon asset many times - all changes sum up in the BurnCertificate. The Custodian also can burn carbon assets for the user viaburn
extrinsic. The user also receives a BurnCertificate.
Here's a repo with source code of a dApp for tokenization flow above: https://github.com/EvercityEcosystem/carbon-dapp
Participants: Issuer (Climate Project) Custodian (for example Evercity) Registry (Registry company that stores Carbon Credits) Standard (Carbon Credits Standard company) Investor (Buyer)
Tokenization
- Issuer has issued carbon credits in a Registry, certified by the Standard which is reflected in the respective registry entry
- Issuer opens account on Evercity DApp and connects it with a personal blockchain wallet
- Issuer creates an application for the tokenization of carbon credits and includes information about the offset (vintage, project ID, amount, etc).
- Custodian receives the application and approves it, notifying the Standard and the Registry. Custodian contacts the Issuer, and transfers the payment;
- Carbon credits are retired in the Registry by the Issuer. In the in the beneficiary field, the Issuer enters a specific information about tokenization on Evercity DApp
Purchase
- Investor opens account on Evercity DApp and connects it with a personal blockchain wallet
- Custodian is doing the KYC on the investor, and makes sure that only verified investor are able to purchase the carbon offsets
- Investor transfers money to the bank account of the Custodian to be able to execute payments
- Investor wants to purchase Carbon Credits, creates an application, including the amount of carbon credits to purchase with the respective price. Investor confirms the transaction
- Everusd money are locked on Investor’s account
- Once the Issuer has approved the purchase application, carbon credits are transferred to Investor’s account, and Issuer receives Everusd
Retirement
- To retire (burn) carbon credits, or retrieve Everusd for money, a user needs to contact the Custodian with the specific application. Custodian does KYC on the beneficiary of the offset retirement.
- Investor retires the carbon credits (burns tokens) on Evercity DApp and states the beneficiary entity / person
- The information about retirement is reflected in the Issuer’s project profile card on Evercity DApp
Please refer to the #[pallet::call]
for documentation on each function.
Add Carbon Assets Module to your Cargo.toml dependencies.
[dependencies]
pallet-carbon-assets = { version = "0.2.2", default-features = false, git = "https://github.com/EvercityEcosystem/carbon-assets.git" }
Also you need some source of Randomness
, for example pallet_randomness_collective_flip
.
Configure construct_runtime!
in runtime/src/lib.rs
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system,
RandomnessCollectiveFlip: pallet_randomness_collective_flip,
...
CarbonAssets: pallet_carbon_assets,
}
);
Configure pallet_carbon_assets::Config
parameter_types! {
pub const CarbonAssetDeposit: Balance = 0;
pub const CarbonAssetAccountDeposit: Balance = 0;
pub const CarbonMetadataDepositBase: Balance = 0;
pub const CarbonMetadataDepositPerByte: Balance = 0;
pub const CarbonApprovalDeposit: Balance = 0;
pub const CarbonStringLimit: u32 = 140;
}
pub use pallet_carbon_assets;
impl pallet_carbon_assets::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Balance = u128;
type Currency = Balances;
type ForceOrigin = frame_system::EnsureRoot<AccountId>;
type AssetDeposit = CarbonAssetDeposit;
type AssetAccountDeposit = CarbonAssetAccountDeposit;
type MetadataDepositBase = CarbonMetadataDepositBase;
type MetadataDepositPerByte = CarbonMetadataDepositPerByte;
type ApprovalDeposit = CarbonApprovalDeposit;
type StringLimit = CarbonStringLimit;
type Freezer = ();
type Extra = ();
type WeightInfo = pallet_carbon_assets::weights::SubstrateWeight<Runtime>;
type Randomness = RandomnessCollectiveFlip;
}
Configure GenesisConfig in node/src/chain_spec.rs
- set Alice as custodian for testnet (or use custom account):
use node_template_runtime::{
AccountId, AuraConfig, ... WASM_BINARY, CarbonAssetsConfig,
};
...
/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
wasm_binary: &[u8],
initial_authorities: Vec<(AuraId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool,
) -> GenesisConfig {
GenesisConfig {
system: SystemConfig {
// Add Wasm runtime to storage.
code: wasm_binary.to_vec(),
},
...
carbon_assets: CarbonAssetsConfig {
custodian: Some(get_account_id_from_seed::<sr25519::Public>("Alice")),
assets: vec![],
metadata: vec![],
accounts: vec![],
}
}
}
Below are assumptions that must be held when using this module. If any of them are violated, the behavior of this module is undefined.
- The total count of assets should be less than
u64::MAX
.
License: Apache-2.0