#[macro_use]
extern crate clap;
extern crate serde_crate as serde;
use std::path::PathBuf;
use std::str::FromStr;
use bitcoin::OutPoint;
use clap::Parser;
use colored::Colorize;
use lnpbp::chain::Chain;
use rgb::fungible::allocation::{AllocatedValue, OutpointValue, UtxobValue};
use rgb::{Consignment, Contract, ContractId, IntoRevealedSeal, StateTransfer};
use rgb121::{Asset, Rgb121};
use seals::txout::CloseMethod;
use stens::AsciiString;
use strict_encoding::{StrictDecode, StrictEncode};
#[derive(Parser, Clone, Debug)]
#[clap(
name = "rgb121",
bin_name = "rgb121",
author,
version,
about = "Command-line tool for working with RGB121 fungible assets"
)]
pub struct Opts {
#[clap(short, long, default_value = "signet", env = "RGB_NETWORK")]
pub network: Chain,
#[clap(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Command {
Issue {
name: AsciiString,
description: Option<AsciiString>,
#[clap(short, long, default_value = "8")]
precision: u8,
allocations: Vec<OutpointValue>,
#[clap(long, validator=parent_validator)]
parent_id: Option<AsciiString>,
#[clap(short, long, default_value = "tapret1st")]
method: CloseMethod,
},
Transfer {
consignment: PathBuf,
#[clap(short = 'u', long = "utxo", required = true)]
outpoints: Vec<OutPoint>,
#[clap(required = true)]
beneficiaries: Vec<UtxobValue>,
#[clap(short, long)]
change: Vec<AllocatedValue>,
output: PathBuf,
},
}
fn main() -> Result<(), String> {
let opts = Opts::parse();
match opts.command {
Command::Issue {
name,
description,
precision,
parent_id,
allocations,
method,
} => {
let contract = Contract::create_rgb121(
opts.network,
name,
description,
precision,
parent_id,
vec![],
vec![],
allocations,
method,
)
.expect("create rgb21 contract failed");
let _asset =
Asset::try_from(&contract).expect("create_rgb121 does not match RGB121 schema");
eprintln!(
"{} {}\n",
"Contract ID:".bright_green(),
contract.contract_id().to_string().bright_yellow()
);
eprintln!("{}", "Contract YAML:".bright_green());
eprintln!("{}", serde_yaml::to_string(contract.genesis()).unwrap());
eprintln!("{}", "Contract JSON:".bright_green());
println!("{}\n", serde_json::to_string(contract.genesis()).unwrap());
eprintln!("{}", "Contract source:".bright_green());
println!("{}\n", contract);
}
Command::Transfer {
consignment,
outpoints,
beneficiaries,
change,
output,
} => {
let transfer = StateTransfer::strict_file_load(consignment).unwrap();
let asset = Asset::try_from(&transfer).unwrap();
let beneficiaries = beneficiaries
.into_iter()
.map(|v| (v.seal_confidential.into(), v.value))
.collect();
let change = change
.into_iter()
.map(|v| (v.into_revealed_seal(), v.value))
.collect();
let outpoints = outpoints.into_iter().collect();
let transition = asset.transfer(outpoints, beneficiaries, change).unwrap();
transition.strict_file_save(output).unwrap();
println!("{}", serde_yaml::to_string(&transition).unwrap());
println!("{}", "Success".bold().bright_green());
}
}
Ok(())
}
fn parent_validator(parent_id: &str) -> Result<(), String> {
let contract = ContractId::from_str(parent_id);
if contract.is_err() {
Err("Parent ID must be a valid contract ID".to_string())
} else {
Ok(())
}
}