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
20 changes: 4 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ concurrency:
cancel-in-progress: true

env:
SIMPLEX_COMMIT: c1e9d8b06231973d81fbaa677cf3f03787104b81
SIMPLEX_VERSION: 0.0.11

jobs:
ci:
Expand All @@ -28,21 +28,9 @@ jobs:
rustup component add rustfmt clippy

- name: Install pinned Simplex CLI
shell: bash
run: |
set -euo pipefail
SIMPLEX_DIR="${SIMPLEX_DIR:-${XDG_CONFIG_HOME:-$HOME}/.simplex}"
mkdir -p "$SIMPLEX_DIR/bin"
curl -fsSL --retry 5 --retry-all-errors --retry-delay 2 \
"https://raw.githubusercontent.com/BlockstreamResearch/smplx/$SIMPLEX_COMMIT/simplexup/simplexup" \
-o "$SIMPLEX_DIR/bin/simplexup"
grep -Fq 'curl -#o "$2" -L "$1"' "$SIMPLEX_DIR/bin/simplexup"
sed -i 's/curl -#o "$2" -L "$1"/curl -#fL --retry 5 --retry-all-errors --retry-delay 2 -o "$2" "$1"/' \
"$SIMPLEX_DIR/bin/simplexup"
chmod +x "$SIMPLEX_DIR/bin/simplexup"
echo "$SIMPLEX_DIR/bin" >> "$GITHUB_PATH"
"$SIMPLEX_DIR/bin/simplexup" -C "$SIMPLEX_COMMIT"
"$SIMPLEX_DIR/bin/simplex" --version
uses: BlockstreamResearch/simplicityhl-toolchain@v0.0.2
with:
components: simplex@${{ env.SIMPLEX_VERSION }}

- name: Generate contract artifacts
working-directory: contracts
Expand Down
23 changes: 4 additions & 19 deletions .github/workflows/contracts-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ concurrency:

env:
CARGO_TERM_COLOR: always
SIMPLEX_COMMIT: c1e9d8b06231973d81fbaa677cf3f03787104b81
SIMPLEX_VERSION: 0.0.11

jobs:
test:
Expand All @@ -40,24 +40,9 @@ jobs:
cache-on-failure: true

- name: Install simplex-cli via simplexup
shell: bash
run: |
set -euo pipefail
BASE_DIR="${XDG_CONFIG_HOME:-$HOME}"
SIMPLEX_DIR="${SIMPLEX_DIR:-$BASE_DIR/.simplex}"
SIMPLEX_BIN_DIR="$SIMPLEX_DIR/bin"
mkdir -p "$SIMPLEX_BIN_DIR"
curl -fsSL --retry 5 --retry-all-errors --retry-delay 2 \
"https://raw.githubusercontent.com/BlockstreamResearch/smplx/$SIMPLEX_COMMIT/simplexup/simplexup" \
-o "$SIMPLEX_BIN_DIR/simplexup"
grep -Fq 'curl -#o "$2" -L "$1"' "$SIMPLEX_BIN_DIR/simplexup"
sed -i 's/curl -#o "$2" -L "$1"/curl -#fL --retry 5 --retry-all-errors --retry-delay 2 -o "$2" "$1"/' \
"$SIMPLEX_BIN_DIR/simplexup"
chmod +x "$SIMPLEX_BIN_DIR/simplexup"

"$SIMPLEX_BIN_DIR/simplexup" -C "$SIMPLEX_COMMIT"
echo "$SIMPLEX_BIN_DIR" >> "$GITHUB_PATH"
"$SIMPLEX_BIN_DIR/simplex" --version
uses: BlockstreamResearch/simplicityhl-toolchain@v0.0.2
with:
components: simplex@${{ env.SIMPLEX_VERSION }}

- name: Generate contract artifacts
shell: bash
Expand Down
32 changes: 19 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ edition = "2024"

[workspace.dependencies]
axum = "0.8.9"
simplex = { package = "smplx-std", version = "0.0.11" }
bip322 = "0.0.11"
bitcoin = "0.32.5"
bitcoincore-rpc = "0.19.0"
Expand Down
2 changes: 1 addition & 1 deletion contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024"

[dependencies]
smplx-std = { git = "https://github.com/BlockstreamResearch/smplx", rev = "c1e9d8b06231973d81fbaa677cf3f03787104b81" }
simplex.workspace = true
thiserror.workspace = true
storm-tree = { path = "../storm-tree" }

Expand Down
2 changes: 1 addition & 1 deletion contracts/Simplex.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# out_dir = "./src/artifacts"

[dependencies]
std = { git = "https://github.com/BlockstreamResearch/simplicityhl-std.git", tag = "v0.1.0" }
std = { git = "https://github.com/BlockstreamResearch/simplicityhl-std.git", tag = "v0.1.0" }

# [regtest]
# mnemonic = "exist carry drive collect lend cereal occur much tiger just involve mean"
Expand Down
2 changes: 1 addition & 1 deletion contracts/simf/auth_helpers/network_auth_test.simf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::network::{StormTreeBloom, assert_network_authorization};
use crate::auth_helpers::network::{StormTreeBloom, assert_network_authorization};

fn main() {
let merkle_root: u256 = witness::MERKLE_ROOT;
Expand Down
24 changes: 12 additions & 12 deletions contracts/simf/tick_asset.simf → contracts/simf/voucher.simf
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,45 @@ use std::lib::op_return::assert_output_is_op_return;

use crate::helper::{get_input_asset, get_input_script_hash, assert_output_preserves_utxo};

/// 1. asset_auth_utxo_input_index, tick_utxo_output_index
/// 1. asset_auth_utxo_input_index, voucher_utxo_output_index
type AssetAuthWit = (u32, u32);
/// 2. script_auth_utxo_input_index, tick_utxo_output_index
/// 2. script_auth_utxo_input_index, voucher_utxo_output_index
type ScriptAuthWit = (u32, u32);
/// 3. auth_signature, tick_utxo_output_index
/// 3. auth_signature, voucher_utxo_output_index
type SignAuthWit = (Signature, u32);
/// 4. storm_eye_input_index
type NetworkAuthWit = u32;

type AuthKindLeft = Either<AssetAuthWit, ScriptAuthWit>;
type AuthKindRight = Either<SignAuthWit, NetworkAuthWit>;

fn assert_tick_utxo_burned(tick_utxo_output_index: u32) {
assert_output_preserves_utxo(tick_utxo_output_index);
assert_output_is_op_return(tick_utxo_output_index);
fn assert_voucher_utxo_burned(voucher_utxo_output_index: u32) {
assert_output_preserves_utxo(voucher_utxo_output_index);
assert_output_is_op_return(voucher_utxo_output_index);
}

/// 1. User spending via the Asset authorization method.
fn user_spend_via_asset_auth(asset_auth_utxo_input_index: u32, tick_utxo_output_index: u32) {
fn user_spend_via_asset_auth(asset_auth_utxo_input_index: u32, voucher_utxo_output_index: u32) {
assert_eq_32(param::AUTH_METHOD, 0);
assert_eq_256(get_input_asset(asset_auth_utxo_input_index), param::AUTH_ASSET_ID);

assert_tick_utxo_burned(tick_utxo_output_index);
assert_voucher_utxo_burned(voucher_utxo_output_index);
}

/// 2. User spending via the Script authorization method.
fn user_spend_via_script_auth(script_auth_utxo_input_index: u32, tick_utxo_output_index: u32) {
fn user_spend_via_script_auth(script_auth_utxo_input_index: u32, voucher_utxo_output_index: u32) {
assert_eq_32(param::AUTH_METHOD, 1);
assert_eq_256(get_input_script_hash(script_auth_utxo_input_index), param::AUTH_SCRIPT_HASH);

assert_tick_utxo_burned(tick_utxo_output_index);
assert_voucher_utxo_burned(voucher_utxo_output_index);
}

/// 3. User spending via the Signature authorization method.
fn user_spend_via_sign_auth(auth_signature: Signature, tick_utxo_output_index: u32) {
fn user_spend_via_sign_auth(auth_signature: Signature, voucher_utxo_output_index: u32) {
assert_eq_32(param::AUTH_METHOD, 2);
jet::bip_0340_verify((param::AUTH_PUBKEY, jet::sig_all_hash()), auth_signature);

assert_tick_utxo_burned(tick_utxo_output_index);
assert_voucher_utxo_burned(voucher_utxo_output_index);
}

/// 4. Network authorized spending.
Expand Down
70 changes: 70 additions & 0 deletions contracts/src/account/core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use simplex::provider::SimplicityNetwork;
use simplex::simplicityhl::elements::{AssetId, Script};
use simplex::transaction::utxo::UTXO;
use simplex::transaction::{
FinalTransaction, PartialInput, PartialOutput, ProgramInput, RequiredSignature,
};

use crate::artifacts::account::AccountProgram;
use crate::artifacts::account::derived_account::{AccountArguments, AccountWitness};

/// The Account covenant: spendable alongside a Storm Eye input.
pub struct Account {
program: AccountProgram,
params: AccountParameters,
}

pub struct AccountParameters {
pub storm_eye_asset_id: AssetId,
pub account_owner_pubkey: [u8; 32],
pub network: SimplicityNetwork,
}

impl Account {
#[must_use]
pub fn new(params: AccountParameters) -> Self {
let program = AccountProgram::new(&AccountArguments {
storm_eye_asset_id: params.storm_eye_asset_id.into_inner().to_byte_array(),
account_owner_pubkey: params.account_owner_pubkey,
});

Self { program, params }
}

#[must_use]
pub fn get_script_pubkey(&self) -> Script {
self.program.get_script_pubkey(&self.params.network)
}

#[must_use]
pub fn get_parameters(&self) -> &AccountParameters {
&self.params
}

pub fn attach_spend(
&self,
ft: &mut FinalTransaction,
account_utxo: &UTXO,
storm_eye_input_index: u32,
) {
ft.add_program_input(
PartialInput::new(account_utxo.clone()),
ProgramInput::new(
Box::new(self.program.as_ref().clone()),
Box::new(AccountWitness {
storm_eye_input_index,
}),
),
RequiredSignature::None,
);
}

/// Adds an output that pays `amount` of `asset_id` to this Account.
pub fn attach_account_output(&self, ft: &mut FinalTransaction, amount: u64, asset_id: AssetId) {
ft.add_output(PartialOutput::new(
self.get_script_pubkey(),
amount,
asset_id,
));
}
}
3 changes: 3 additions & 0 deletions contracts/src/account/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod core;

pub use core::{Account, AccountParameters};
2 changes: 2 additions & 0 deletions contracts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod artifacts;

pub mod account;
pub mod auth;
pub mod treasury;
pub mod voucher;
69 changes: 69 additions & 0 deletions contracts/src/voucher/core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use simplex::simplicityhl::elements::schnorr::XOnlyPublicKey;
use simplex::simplicityhl::elements::{AssetId, Script};
use simplex::transaction::utxo::UTXO;
use simplex::transaction::{FinalTransaction, PartialInput, PartialOutput, ProgramInput};

use crate::artifacts::voucher::VoucherProgram;
use crate::voucher::{VoucherParameters, VoucherSpendPath};

/// The Voucher covenant: a burn-after-use, network-issued proof token.
pub struct Voucher {
program: VoucherProgram,
params: VoucherParameters,
}

impl Voucher {
#[must_use]
pub fn new(params: VoucherParameters) -> Self {
Self {
program: VoucherProgram::new(&params.build_arguments()),
params,
}
}

#[must_use]
pub fn new_with_taproot_pubkey(params: VoucherParameters, pub_key: XOnlyPublicKey) -> Self {
Self {
program: VoucherProgram::new(&params.build_arguments()).with_taproot_pubkey(pub_key),
params,
}
}

#[must_use]
pub fn get_script_pubkey(&self) -> Script {
self.program.get_script_pubkey(&self.params.network)
}

#[must_use]
pub fn get_parameters(&self) -> &VoucherParameters {
&self.params
}

/// Attaches a spend of `voucher_utxo` along the given spending path.
pub fn attach_spend(
&self,
ft: &mut FinalTransaction,
voucher_utxo: &UTXO,
path: VoucherSpendPath,
) {
let required_signature = path.required_signature();

ft.add_program_input(
PartialInput::new(voucher_utxo.clone()),
ProgramInput::new(
Box::new(self.program.as_ref().clone()),
Box::new(path.build_witness()),
),
required_signature,
);
}

/// Adds an output that pays `amount` of `asset_id` to this Voucher.
pub fn attach_voucher_output(&self, ft: &mut FinalTransaction, amount: u64, asset_id: AssetId) {
ft.add_output(PartialOutput::new(
self.get_script_pubkey(),
amount,
asset_id,
));
}
}
Loading
Loading