mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
contract/money: Add stub for minting arbitrary tokens.
This commit is contained in:
@@ -21,9 +21,9 @@ contract "Mint_V1" {
|
||||
Base spend_hook,
|
||||
# Data passed from this coin to the invoked contract
|
||||
Base user_data,
|
||||
# Random blinding factor for value commitment
|
||||
# Random blinding factor for the value commitment
|
||||
Scalar value_blind,
|
||||
# Random blinding facfor for the token ID
|
||||
# Random blinding factor for the token ID
|
||||
Scalar token_blind,
|
||||
}
|
||||
|
||||
|
||||
74
src/contract/money/proof/token_mint_v1.zk
Normal file
74
src/contract/money/proof/token_mint_v1.zk
Normal file
@@ -0,0 +1,74 @@
|
||||
constant "TokenMint_V1" {
|
||||
EcFixedPointShort VALUE_COMMIT_VALUE,
|
||||
EcFixedPoint VALUE_COMMIT_RANDOM,
|
||||
EcFixedPointBase NULLIFIER_K,
|
||||
}
|
||||
|
||||
contract "TokenMint_V1" {
|
||||
# Token mint authority secret
|
||||
Base mint_authority,
|
||||
# Token supply
|
||||
Base supply,
|
||||
# Fixed supply
|
||||
Base fixed_supply,
|
||||
# Recipient's public key x coordinate
|
||||
Base rcpt_x,
|
||||
# Recipient's public key y coordinate
|
||||
Base rcpt_y,
|
||||
# Unique serial number corresponding to this coin
|
||||
Base serial,
|
||||
# Random blinding factor for coin
|
||||
Base coin_blind,
|
||||
# Allows composing this ZK proof to invoke other contracts
|
||||
Base spend_hook,
|
||||
# Data passed from this coin to the invoked contract
|
||||
Base user_data,
|
||||
# Random blinding factor for the value commitment
|
||||
Scalar value_blind,
|
||||
# Random blinding factor for the token ID
|
||||
Scalar token_blind,
|
||||
}
|
||||
|
||||
circuit "TokenMint_V1" {
|
||||
# Derive public key for the mint authority
|
||||
mint_public = ec_mul_base(mint_authority, NULLIFIER_K);
|
||||
mint_x = ec_get_x(mint_public);
|
||||
mint_y = ec_get_y(mint_public);
|
||||
constrain_instance(mint_x);
|
||||
constrain_instance(mint_y);
|
||||
|
||||
# Derive the token ID
|
||||
token_id = poseidon_hash(mint_x, mint_y);
|
||||
constrain_instance(token_id);
|
||||
|
||||
# Constrain whether this token has a fixed supply or not.
|
||||
# In case it is, subsequent mints will not be allowed.
|
||||
bool_check(fixed_supply);
|
||||
constrain_instance(fixed_supply);
|
||||
|
||||
# Poseidon hash of the coin
|
||||
C = poseidon_hash(
|
||||
rcpt_x,
|
||||
rcpt_y,
|
||||
supply,
|
||||
token_id,
|
||||
spend_hook,
|
||||
user_data,
|
||||
coin_blind,
|
||||
);
|
||||
constrain_instance(C);
|
||||
|
||||
# Pedersen commitment for the coin's value
|
||||
vcv = ec_mul_short(supply, VALUE_COMMIT_VALUE);
|
||||
vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
|
||||
value_commit = ec_add(vcv, vcr);
|
||||
constrain_instance(ec_get_x(value_commit));
|
||||
constrain_instance(ec_get_y(value_commit));
|
||||
|
||||
# Pedersen commitment for the token ID
|
||||
tcv = ec_mul_base(token_id, NULLIFIER_K);
|
||||
tcr = ec_mul(token_blind, VALUE_COMMIT_RANDOM);
|
||||
token_commit = ec_add(tcv, tcr);
|
||||
constrain_instance(ec_get_x(token_commit));
|
||||
constrain_instance(ec_get_y(token_commit));
|
||||
}
|
||||
@@ -47,6 +47,7 @@ pub enum MoneyFunction {
|
||||
OtcSwap = 0x01,
|
||||
Stake = 0x02,
|
||||
Unstake = 0x03,
|
||||
Mint = 0x04,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for MoneyFunction {
|
||||
@@ -58,6 +59,7 @@ impl TryFrom<u8> for MoneyFunction {
|
||||
0x01 => Ok(Self::OtcSwap),
|
||||
0x02 => Ok(Self::Stake),
|
||||
0x03 => Ok(Self::Unstake),
|
||||
0x04 => Ok(Self::Mint),
|
||||
_ => Err(ContractError::InvalidFunction),
|
||||
}
|
||||
}
|
||||
@@ -84,6 +86,7 @@ darkfi_sdk::define_contract!(
|
||||
// These are the different sled trees that will be created
|
||||
pub const MONEY_CONTRACT_COIN_ROOTS_TREE: &str = "coin_roots";
|
||||
pub const MONEY_CONTRACT_NULLIFIERS_TREE: &str = "nullifiers";
|
||||
pub const MONEY_CONTRACT_FIXED_SUPPLY_TREE: &str = "fixed_supply_tokens";
|
||||
pub const MONEY_CONTRACT_INFO_TREE: &str = "info";
|
||||
|
||||
// This is a key inside the info tree
|
||||
@@ -94,6 +97,8 @@ pub const MONEY_CONTRACT_FAUCET_PUBKEYS: &str = "faucet_pubkeys";
|
||||
pub const MONEY_CONTRACT_ZKAS_MINT_NS_V1: &str = "Mint_V1";
|
||||
/// zkas burn contract namespace
|
||||
pub const MONEY_CONTRACT_ZKAS_BURN_NS_V1: &str = "Burn_V1";
|
||||
/// zkas token mint contract namespace
|
||||
pub const MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1: &str = "TokenMint_V1";
|
||||
|
||||
/// This function runs when the contract is (re)deployed and initialized.
|
||||
#[cfg(not(feature = "no-entrypoint"))]
|
||||
@@ -111,6 +116,7 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
};
|
||||
let mint_v1_bincode = include_bytes!("../proof/mint_v1.zk.bin");
|
||||
let burn_v1_bincode = include_bytes!("../proof/burn_v1.zk.bin");
|
||||
let token_mint_v1_bincode = include_bytes!("../proof/token_mint_v1.zk.bin");
|
||||
|
||||
/* TODO: Do I really want to make zkas a dependency? Yeah, in the future.
|
||||
For now we take anything.
|
||||
@@ -125,6 +131,7 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
*/
|
||||
db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_MINT_NS_V1), &mint_v1_bincode[..])?;
|
||||
db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_BURN_NS_V1), &burn_v1_bincode[..])?;
|
||||
db_set(zkas_db, &serialize(&MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1), &token_mint_v1_bincode[..])?;
|
||||
|
||||
// Set up a database tree to hold Merkle roots
|
||||
let _ = match db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE) {
|
||||
@@ -138,6 +145,12 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
Err(_) => db_init(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?,
|
||||
};
|
||||
|
||||
// Set up a database tree to hold the set of fixed-supply tokens
|
||||
let _ = match db_lookup(cid, MONEY_CONTRACT_FIXED_SUPPLY_TREE) {
|
||||
Ok(v) => v,
|
||||
Err(_) => db_init(cid, MONEY_CONTRACT_FIXED_SUPPLY_TREE)?,
|
||||
};
|
||||
|
||||
// Set up a database tree for arbitrary data
|
||||
let info_db = match db_lookup(cid, MONEY_CONTRACT_INFO_TREE) {
|
||||
Ok(v) => v,
|
||||
@@ -231,6 +244,7 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
|
||||
MoneyFunction::Stake => unimplemented!(),
|
||||
MoneyFunction::Unstake => unimplemented!(),
|
||||
MoneyFunction::Mint => unimplemented!(),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
@@ -444,6 +458,11 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
msg!("[Unstake] Entered match arm");
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
MoneyFunction::Mint => {
|
||||
msg!("[Mint] Entered match arm");
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,5 +494,6 @@ fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
|
||||
|
||||
MoneyFunction::Stake => unimplemented!(),
|
||||
MoneyFunction::Unstake => unimplemented!(),
|
||||
MoneyFunction::Mint => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,23 @@
|
||||
*/
|
||||
|
||||
use darkfi_serial::{SerialDecodable, SerialEncodable};
|
||||
use lazy_static::lazy_static;
|
||||
use pasta_curves::{group::ff::PrimeField, pallas};
|
||||
|
||||
use super::{poseidon_hash, PublicKey, SecretKey};
|
||||
use crate::error::ContractError;
|
||||
|
||||
lazy_static! {
|
||||
// The idea here is that 0 is not a valid x coordinate for any pallas point,
|
||||
// therefore a signature cannot be produced for such IDs. This allows us to
|
||||
// avoid hardcoding contract IDs for arbitrary contract deployments, because
|
||||
// the contracts with 0 as their x coordinate can never have a valid signature.
|
||||
|
||||
/// Native DARK token ID
|
||||
pub static ref DARK_TOKEN_ID: TokenId =
|
||||
TokenId::from(poseidon_hash([pallas::Base::zero(), pallas::Base::from(42)]));
|
||||
}
|
||||
|
||||
/// TokenId represents an on-chain identifier for a certain token.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct TokenId(pallas::Base);
|
||||
|
||||
Reference in New Issue
Block a user