Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/contracts/src/programs/asset_auth/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,8 @@ impl SimplexProgram for AssetAuth {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
AssetAuthProgram::SOURCE
}
}
8 changes: 8 additions & 0 deletions crates/contracts/src/programs/asset_auth_vault/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ impl SimplexProgram for ActiveAssetAuthVault {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
AssetAuthVaultProgram::SOURCE
}
}

impl SimplexProgram for FinalizedAssetAuthVault {
Expand All @@ -196,4 +200,8 @@ impl SimplexProgram for FinalizedAssetAuthVault {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
AssetAuthVaultProgram::SOURCE
}
}
68 changes: 20 additions & 48 deletions crates/contracts/src/programs/issuance_factory/core.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use simplex::provider::ProviderTrait;
use simplex::simplicityhl::elements::{AssetId, Script, Transaction};
use simplex::simplicityhl::elements::{hex::ToHex, schnorr::XOnlyPublicKey};
use simplex::transaction::partial_input::IssuanceInput;
use simplex::transaction::{
FinalTransaction, IssuanceDetails, PartialOutput, RequiredSignature, UTXO,
Expand All @@ -11,18 +10,16 @@ use crate::artifacts::issuance_factory::IssuanceFactoryProgram;
use crate::programs::issuance_factory::{
IssuanceFactoryError, IssuanceFactoryParameters, IssuanceFactoryWitnessBranch,
};
use crate::programs::program::SimplexProgram;

const CREATION_OP_RETURN_OUTPUT_INDEX: usize = 1;
use crate::programs::program::{MetadataProgram, SimplexProgram};
use crate::utils::op_return_payload;

pub struct IssuanceFactory {
program: IssuanceFactoryProgram,
parameters: IssuanceFactoryParameters,
}

// TODO: encode constants to the factory asset amount or creation OP_RETURN
pub const PRE_LOCK_ISSUING_UTXOS_COUNT: u8 = 2;
pub const PRE_LOCK_REISSUANCE_FLAGS: u64 = 0;
pub const ISSUANCE_FACTORY_CREATION_OP_RETURN_DATA_LENGTH: usize = 32;

impl IssuanceFactory {
pub fn new(parameters: IssuanceFactoryParameters) -> Self {
Self {
Expand All @@ -35,30 +32,25 @@ impl IssuanceFactory {
tx: &Transaction,
provider: &impl ProviderTrait,
) -> Result<Self, IssuanceFactoryError> {
if tx.output.len() < 2 || !tx.output[1].is_null_data() {
if tx.output.len() <= CREATION_OP_RETURN_OUTPUT_INDEX
|| !tx.output[CREATION_OP_RETURN_OUTPUT_INDEX].is_null_data()
{
return Err(IssuanceFactoryError::NotAnIssuanceFactoryCreationTx(
tx.txid(),
));
}

let mut op_return_instr_iter = tx.output[5].script_pubkey.instructions_minimal();

op_return_instr_iter.next();

let op_return_bytes = op_return_instr_iter
.next()
.unwrap()
.unwrap()
.push_bytes()
.unwrap();
let op_return_bytes =
op_return_payload(&tx.output[CREATION_OP_RETURN_OUTPUT_INDEX].script_pubkey)
.ok_or_else(|| IssuanceFactoryError::NotAnIssuanceFactoryCreationTx(tx.txid()))?;

let owner_pubkey =
IssuanceFactory::decode_creation_op_return_data(op_return_bytes.to_vec())?;
let creation_op_return_data =
IssuanceFactory::decode_metadata_op_return(op_return_bytes.to_vec())?;

let issuance_factory_parameters = IssuanceFactoryParameters {
issuing_utxos_count: PRE_LOCK_ISSUING_UTXOS_COUNT,
reissuance_flags: PRE_LOCK_REISSUANCE_FLAGS,
owner_pubkey,
issuing_utxos_count: creation_op_return_data.issuing_utxos_count,
reissuance_flags: creation_op_return_data.reissuance_flags,
owner_pubkey: creation_op_return_data.owner_pubkey,
network: *provider.get_network(),
};

Expand All @@ -69,30 +61,6 @@ impl IssuanceFactory {
&self.parameters
}

pub fn decode_creation_op_return_data(
op_return_bytes: Vec<u8>,
) -> Result<XOnlyPublicKey, IssuanceFactoryError> {
if op_return_bytes.len() != ISSUANCE_FACTORY_CREATION_OP_RETURN_DATA_LENGTH {
return Err(IssuanceFactoryError::InvalidCreationOpReturnDataLength {
expected: ISSUANCE_FACTORY_CREATION_OP_RETURN_DATA_LENGTH,
actual: op_return_bytes.len(),
});
}

let owner_pubkey = XOnlyPublicKey::from_slice(op_return_bytes.as_slice())
.map_err(|_| IssuanceFactoryError::InvalidOpReturnBytes(op_return_bytes.to_hex()))?;

Ok(owner_pubkey)
}

pub fn encode_creation_op_return_data(&self) -> Vec<u8> {
let mut op_return_data =
Vec::with_capacity(ISSUANCE_FACTORY_CREATION_OP_RETURN_DATA_LENGTH);
op_return_data.extend_from_slice(&self.parameters.owner_pubkey.serialize());

op_return_data
}

pub fn attach_creation(
&self,
ft: &mut FinalTransaction,
Expand All @@ -101,7 +69,7 @@ impl IssuanceFactory {
) {
self.add_program_output(ft, factory_asset_id, factory_asset_amount);

let op_return_data = self.encode_creation_op_return_data();
let op_return_data = self.encode_metadata_op_return();

ft.add_output(PartialOutput::new(
Script::new_op_return(&op_return_data),
Expand Down Expand Up @@ -171,4 +139,8 @@ impl SimplexProgram for IssuanceFactory {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
IssuanceFactoryProgram::SOURCE
}
}
97 changes: 97 additions & 0 deletions crates/contracts/src/programs/issuance_factory/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use simplex::simplicityhl::elements::{hex::ToHex, schnorr::XOnlyPublicKey};

use crate::programs::issuance_factory::{IssuanceFactory, IssuanceFactoryError};
use crate::programs::program::{
CreationOpReturnData, MetadataProgram, PROGRAM_ID_LENGTH, ProgramId, SimplexProgram,
};

const OWNER_PUBKEY_LENGTH: usize = 32;
const CREATION_OP_RETURN_DATA_LENGTH: usize = PROGRAM_ID_LENGTH
+ std::mem::size_of::<u8>()
+ std::mem::size_of::<u64>()
+ OWNER_PUBKEY_LENGTH;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IssuanceFactoryCreationOpReturnData {
pub program_id: ProgramId,
pub issuing_utxos_count: u8,
pub reissuance_flags: u64,
pub owner_pubkey: XOnlyPublicKey,
}

impl IssuanceFactoryCreationOpReturnData {
pub fn new(
program_id: ProgramId,
issuing_utxos_count: u8,
reissuance_flags: u64,
owner_pubkey: XOnlyPublicKey,
) -> Self {
Self {
program_id,
issuing_utxos_count,
reissuance_flags,
owner_pubkey,
}
}
}

impl CreationOpReturnData for IssuanceFactoryCreationOpReturnData {
type Error = IssuanceFactoryError;

const DATA_LENGTH: usize = CREATION_OP_RETURN_DATA_LENGTH;

fn decode(op_return_bytes: &[u8]) -> Result<Self, Self::Error> {
Self::validate_length(op_return_bytes, |expected, actual| {
IssuanceFactoryError::InvalidCreationOpReturnDataLength { expected, actual }
})?;

let mut cursor = 0;

let program_id = Self::decode_program_id(op_return_bytes);
cursor += PROGRAM_ID_LENGTH;

let issuing_utxos_count = op_return_bytes[cursor];
cursor += std::mem::size_of::<u8>();

let reissuance_flags = u64::from_le_bytes(
op_return_bytes[cursor..cursor + std::mem::size_of::<u64>()]
.try_into()
.expect("reissuance flags length is fixed"),
);
cursor += std::mem::size_of::<u64>();

let owner_pubkey_bytes = &op_return_bytes[cursor..];
let owner_pubkey = XOnlyPublicKey::from_slice(owner_pubkey_bytes)
.map_err(|_| IssuanceFactoryError::InvalidOpReturnBytes(op_return_bytes.to_hex()))?;

Ok(Self {
program_id,
issuing_utxos_count,
reissuance_flags,
owner_pubkey,
})
}

fn encode(&self) -> Vec<u8> {
let mut op_return_data = Vec::with_capacity(Self::DATA_LENGTH);
op_return_data.extend_from_slice(&self.program_id);
op_return_data.push(self.issuing_utxos_count);
op_return_data.extend_from_slice(&self.reissuance_flags.to_le_bytes());
op_return_data.extend_from_slice(&self.owner_pubkey.serialize());

op_return_data
}
}

impl MetadataProgram for IssuanceFactory {
type Metadata = IssuanceFactoryCreationOpReturnData;

fn build_metadata(&self) -> Self::Metadata {
IssuanceFactoryCreationOpReturnData::new(
self.get_program_id(),
self.get_parameters().issuing_utxos_count,
self.get_parameters().reissuance_flags,
self.get_parameters().owner_pubkey,
)
}
}
2 changes: 2 additions & 0 deletions crates/contracts/src/programs/issuance_factory/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod core;
mod error;
mod metadata;
mod params;
mod witness;

pub use core::IssuanceFactory;
pub use error::IssuanceFactoryError;
pub use metadata::IssuanceFactoryCreationOpReturnData;
pub use params::IssuanceFactoryParameters;
pub use witness::IssuanceFactoryWitnessBranch;
4 changes: 4 additions & 0 deletions crates/contracts/src/programs/lending/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,8 @@ impl SimplexProgram for Lending {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
LendingProgram::SOURCE
}
}
4 changes: 4 additions & 0 deletions crates/contracts/src/programs/ownable_script_auth/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,8 @@ impl SimplexProgram for OwnableScriptAuth {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
OwnableScriptAuthProgram::SOURCE
}
}
60 changes: 13 additions & 47 deletions crates/contracts/src/programs/pre_lock/core.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use simplex::program::Program;

use simplex::provider::{ProviderTrait, SimplicityNetwork};
use simplex::simplicityhl::elements::{
AssetId, Script, Transaction, hex::ToHex, secp256k1_zkp::XOnlyPublicKey,
};
use simplex::simplicityhl::elements::{AssetId, Script, Transaction};
use simplex::transaction::{FinalTransaction, PartialOutput, RequiredSignature, UTXO};
use simplex::utils::hash_script;

use crate::artifacts::pre_lock::PreLockProgram;
use crate::programs::lending::Lending;
use crate::programs::pre_lock::{PreLockError, PreLockParameters, PreLockWitnessBranch};
use crate::programs::program::SimplexProgram;
use crate::programs::program::{MetadataProgram, SimplexProgram};
use crate::programs::script_auth::{ScriptAuth, ScriptAuthWitnessParams};
use crate::utils::op_return_payload;
use crate::utils::{FirstNFTParameters, LendingOfferParameters, SecondNFTParameters};

pub struct PreLock {
Expand All @@ -20,7 +19,6 @@ pub struct PreLock {
}

pub const UTILITY_NFTS_COUNT: usize = 4;
pub const PRE_LOCK_CREATION_OP_RETURN_DATA_LENGTH: usize = 64;

impl PreLock {
pub fn new(parameters: PreLockParameters) -> Self {
Expand Down Expand Up @@ -79,29 +77,20 @@ impl PreLock {
&pre_collateral_tx.output[prev_collateral_outpoint.vout as usize].script_pubkey,
);

let mut op_return_instr_iter = tx.output[5].script_pubkey.instructions_minimal();
let op_return_bytes = op_return_payload(&tx.output[5].script_pubkey)
.ok_or_else(|| PreLockError::NotAPreLockCreationTx(tx.txid()))?;

op_return_instr_iter.next();

let op_return_bytes = op_return_instr_iter
.next()
.unwrap()
.unwrap()
.push_bytes()
.unwrap();

let (borrower_pubkey, principal_asset_id) =
PreLock::decode_creation_op_return_data(op_return_bytes.to_vec()).unwrap();
let creation_op_return_data = PreLock::decode_metadata_op_return(op_return_bytes.to_vec())?;

let pre_lock_parameters = PreLockParameters {
collateral_asset_id,
principal_asset_id,
principal_asset_id: creation_op_return_data.principal_asset_id,
first_parameters_nft_asset_id,
second_parameters_nft_asset_id,
borrower_nft_asset_id,
lender_nft_asset_id,
offer_parameters,
borrower_pubkey,
borrower_pubkey: creation_op_return_data.borrower_pubkey,
borrower_output_script_hash: collateral_script_hash,
network: *provider.get_network(),
};
Expand All @@ -113,33 +102,6 @@ impl PreLock {
&self.parameters
}

pub fn decode_creation_op_return_data(
op_return_bytes: Vec<u8>,
) -> Result<(XOnlyPublicKey, AssetId), PreLockError> {
if op_return_bytes.len() != PRE_LOCK_CREATION_OP_RETURN_DATA_LENGTH {
return Err(PreLockError::InvalidCreationOpReturnDataLength {
expected: PRE_LOCK_CREATION_OP_RETURN_DATA_LENGTH,
actual: op_return_bytes.len(),
});
}

let (op_return_pub_key, op_return_asset_id) = op_return_bytes.split_at(32);

let principal_asset_id = AssetId::from_slice(op_return_asset_id)?;
let borrower_public_key = XOnlyPublicKey::from_slice(op_return_pub_key)
.map_err(|_| PreLockError::InvalidOpReturnBytes(op_return_pub_key.to_hex()))?;

Ok((borrower_public_key, principal_asset_id))
}

pub fn encode_creation_op_return_data(&self) -> Vec<u8> {
let mut op_return_data = Vec::with_capacity(PRE_LOCK_CREATION_OP_RETURN_DATA_LENGTH);
op_return_data.extend_from_slice(&self.parameters.borrower_pubkey.serialize());
op_return_data.extend_from_slice(&self.parameters.principal_asset_id.into_inner().0);

op_return_data
}

pub fn attach_creation(&self, ft: &mut FinalTransaction, parameter_amounts_decimals: u8) {
let (first_parameters_nft_amount, second_parameters_nft_amount) = self
.parameters
Expand Down Expand Up @@ -167,7 +129,7 @@ impl PreLock {
utility_nfts_script_auth.attach_creation(ft, self.parameters.borrower_nft_asset_id, 1);
utility_nfts_script_auth.attach_creation(ft, self.parameters.lender_nft_asset_id, 1);

let op_return_data = self.encode_creation_op_return_data();
let op_return_data = self.encode_metadata_op_return();

ft.add_output(PartialOutput::new(
Script::new_op_return(&op_return_data),
Expand Down Expand Up @@ -292,4 +254,8 @@ impl SimplexProgram for PreLock {
fn get_network(&self) -> &SimplicityNetwork {
&self.parameters.network
}

fn get_program_source_code(&self) -> &'static str {
PreLockProgram::SOURCE
}
}
Loading
Loading