3个不稳定版本

0.2.4 2024年1月16日
0.2.0 2021年11月4日
0.1.2 2021年3月23日

#796 in 神奇豆子


5 crates 中使用

MPL-2.0 许可证

185KB
3.5K SLoC

Sapio

欢迎!

Sapio是一个用于创建可组合的多事务比特币智能合约的框架。

萨皮奥有何不同?

Sapio帮助您构建第三方无法知晓的支付协议规范。

例如,使用萨皮奥,您可以生成一个代表您和您的朋友之间的闪电通道的地址,并将该地址提供给第三方服务,例如交易所,让他们创建通道,而无需您或您的朋友进行任何签名交互,无需任何信任方,也无法区分您的地址与其他地址。

这仅仅是萨皮奥能帮助您完成的事情的冰山一角。

更多...

在萨皮奥之前,大多数比特币智能合约主要关注谁可以在何时赎回代币以及需要什么解锁条件(参见Ivy,Policy/Miniscript等)。一些语言,如BitML,更注重多事务和多方使用案例。

萨皮奥特别关注使用BIP-119 OP_CHECKTEMPLATEVERIFY 的交易。 OP_CHECKTEMPLATEVERIFY 使比特币脚本能够支持无需信任设置的复杂多步骤智能合约。

Sapio是一个工具,用于以简单的方式定义此类智能合约并导出易于集成的API来管理开放合约。使用萨皮奥,您可以将之前可能需要数月或数年才能完成的比特币内部精调项目缩短到20分钟,并获得一个完全功能的比特币应用程序。

Sapio具有内置的智能功能,可帮助开发人员设计安全的智能合约并降低资金损失的风险。

有关Sapio的更多信息,请查看Jeremy的Reckless VR Talk Sapio: 使用OP_CTV的比特币状态智能合约幻灯片

展示金钱!Sapio快速入门课程

快速安装

克隆项目

git clone https://github.com/sapio-lang/sapio

安装Rust (https://www.rust-lang.net.cn/learn/get-started)

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

现在您可以运行

cargo run --example server  --features ws

这启动了一个可以编译和运行Sapio合约的websocket服务器!您可以连接到 tux 以运行交互式会话。

学习Sapio

让我们看看一些示例Sapio合约(更多示例请参阅 示例合约)。

所有合约都有三个基本部分:结构定义、一些方法集合和一个Contract trait实现。

/// deriving these on Something let it interface with external
/// interfaces easily
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct Something {
    /* omitted */
}

/// Something's methods. Note 'a required for macros
impl Something {
    /* omitted */
}

/// Something's Contract trait binding
impl Contract for Something {
    /// [Optional] declares the unlocking conditions
    declare! {finish, /*omitted*/}
    /// [Optional] declares the CTV next steps
    declare! {then, /*omitted*/}
    /// [Optional] declares the updatable next steps and ArgType
    declare! {updatable<ArgType>, /*omitted*/}
    /// note:
    /// If no updatable, this is explicitly required if not using a nightly
    /// compiler.
    declare! {non updatable}
}

让我们看看一些示例

一个基本的按公钥付款合约可以生成如下

/// Pay To Public Key Sapio Contract
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct PayToPublicKey {
    key: bitcoin::PublicKey,
}

impl PayToPublicKey {
    guard! {fn with_key(self, ctx) { Clause::Key(self.key) }}
}

impl Contract for PayToPublicKey {
    declare! {finish, Self::with_key}
    declare! {non updatable}
}

现在让我们看看一个担保合约。这里可以是Alice和担保、Bob和担保,或者Alice和Bob来花费资金。条款是通过(修改版的)rust-miniscript定义的。

/// Basic Escrowing Contract
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct BasicEscrow {
    alice: bitcoin::PublicKey,
    bob: bitcoin::PublicKey,
    escrow: bitcoin::PublicKey,
}

impl BasicEscrow {
    guard! {
        fn redeem(self, ctx) {
            Clause::Threshold(
                1,
                vec![
                    Clause::Threshold(2, vec![Clause::Key(self.alice), Clause::Key(self.bob)]),
                    Clause::And(vec![
                        Clause::Key(self.escrow),
                        Clause::Threshold(1, vec![Clause::Key(self.alice), Clause::Key(self.bob)]),
                    ]),
                ],
            )
        }
    }
}

impl Contract for BasicEscrow {
    declare! {finish, Self::redeem}
    declare! {non updatable}
}

我们也可以将其写得更清楚一些


/// Basic Escrowing Contract, written more expressively
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct BasicEscrow2 {
    alice: bitcoin::PublicKey,
    bob: bitcoin::PublicKey,
    escrow: bitcoin::PublicKey,
}

impl BasicEscrow2 {
    guard! {
        fn use_escrow(self, ctx) {
            Clause::And(vec![
                Clause::Key(self.escrow),
                Clause::Threshold(2, vec![Clause::Key(self.alice), Clause::Key(self.bob)]),
            ])
        }
    }
    guard! {
        fn cooperate(self, ctx) { Clause::And(vec![Clause::Key(self.alice), Clause::Key(self.bob)]) }
    }
}

impl Contract for BasicEscrow2 {
    declare! {finish, Self::use_escrow, Self::cooperate}
    declare! {non updatable}
}

到目前为止,我们还没有使用Sapio的任何CheckTemplateVerify功能。这些都可以在比特币中今天完成。

但是Sapio让我们更进一步。如果我们想防止Alice和担保或Bob和担保作弊怎么办?

/// Trustless Escrowing Contract
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct TrustlessEscrow {
    alice: bitcoin::PublicKey,
    bob: bitcoin::PublicKey,
    alice_escrow: (CoinAmount, bitcoin::Address),
    bob_escrow: (CoinAmount, bitcoin::Address),
}

impl TrustlessEscrow {
    guard! {
    fn cooperate (self, ctx ) { Clause::And(vec![Clause::Key(self.alice), Clause::Key(self.bob)]) }
    }
    then! {fn use_escrow(self, ctx) {
        ctx.template()
            .add_output(
                self.alice_escrow.0.try_into()?,
                &Compiled::from_address(self.alice_escrow.1.clone(), None),
                None)?
            .add_output(
                self.bob_escrow.0.try_into()?,
                &Compiled::from_address(self.bob_escrow.1.clone(), None),
                None)?
            .set_sequence(0, RelTime::try_from(std::time::Duration::from_secs(10*24*60*60))?.into())?.into()
    }}
}

impl Contract for TrustlessEscrow {
    declare! {finish, Self::cooperate}
    declare! {then, Self::use_escrow}
    declare! {non updatable}
}

现在有了TrustlessEscrow,我们做了一些不同的处理。一个then!设计符告诉合约编译器添加一个分支,如果该分支被采取,则必须创建返回的交易。我们还为Alice和Bob传递了一个子合约,以便我们可以在更高层次上指定他们接收的付款类型。最后,我们使用对set_sequence的调用来指定我们应该等待10天才能使用担保(如果我们想的话,也可以将其作为参数传递)。

Sapio将确保我们的合约的所有路径都有足够的资金,只损失费用(用户可配置)。

有用的提示

调试宏

首先,您需要通过rustup default nightly使用夜间编译器。

然后,您可以运行(例如)

cargo rustc --example=server --features="ws" -- -Zunstable-options --pretty=expanded

这将展开示例"服务器"中的所有宏。

依赖项

~13MB
~159K SLoC