在 Sway 中,断言是返回布尔值且没有任何副作用(它们是纯粹的)的程序。断言地址可以拥有资产。断言地址是从编译后的字节码生成的,与比特币中使用的 P2SH
地址相同。用户可以像发送给任何其他地址一样无缝地将资产发送到断言地址。要花费断言资金,用户必须提供断言的原始 byte code
和 断言数据
。在执行 byte code
时将使用 断言数据
,如果断言成功验证,则可以转移资金。
让我们考虑以下断言示例:
predicate;
fn main(a: u32, b: u64) -> bool {
b == a.as_u64()
}
我们将看到一个完整的示例,使用 SDK 从断言中发送和接收资金。
首先,我们设置钱包和一个节点实例。调用 abigen!
宏将为我们生成断言中指定的所有类型,以及两个自定义结构体:
encode_data
函数,可以方便地为我们编码主函数的所有参数。 注意:
abigen!
宏将向断言的name
字段附加Encoder
和Configurables
。例如,name="MyPredicate"
将导致两个名为MyPredicateEncoder
和MyPredicateConfigurables
的结构体。
let asset_id = AssetId::zeroed();
let wallets_config = WalletsConfig::new_multiple_assets(
2,
vec![AssetConfig {
id: asset_id,
num_coins: 1,
coin_amount: 1_000,
}],
);
let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await?;
let first_wallet = &wallets[0];
let second_wallet = &wallets[1];
abigen!(Predicate(
name = "MyPredicate",
abi = "e2e/sway/predicates/basic_predicate/out/release/basic_predicate-abi.json"
));
一旦我们使用 forc build
编译了我们的断言,我们就可以通过 Predicate::load_from
创建一个 Predicate
实例。然后可以将 encode_data
的结果设置到加载的断言上。
let predicate_data = MyPredicateEncoder::default().encode_data(4096, 4096)?;
let code_path = "../../e2e/sway/predicates/basic_predicate/out/release/basic_predicate.bin";
let predicate: Predicate = Predicate::load_from(code_path)?
.with_provider(first_wallet.try_provider()?.clone())
.with_data(predicate_data);
接下来,使用第一个钱包在此断言中锁定一些资产:
// First wallet transfers amount to predicate.
first_wallet
.transfer(predicate.address(), 500, asset_id, TxPolicies::default())
.await?;
// Check predicate balance.
let balance = predicate.get_asset_balance(&AssetId::zeroed()).await?;
assert_eq!(balance, 500);
然后,我们可以通过 Account 特性转移由断言拥有的资产:
let amount_to_unlock = 500;
predicate
.transfer(
second_wallet.address(),
amount_to_unlock,
asset_id,
TxPolicies::default(),
)
.await?;
// Predicate balance is zero.
let balance = predicate.get_asset_balance(&AssetId::zeroed()).await?;
assert_eq!(balance, 0);
// Second wallet balance is updated.
let balance = second_wallet.get_asset_balance(&AssetId::zeroed()).await?;
assert_eq!(balance, 1500);
与合约和脚本一样,您可以在 predicates
中定义可配置常量,在断言执行期间可以更改。以下是定义常量的示例。
#[allow(dead_code)]
enum EnumWithGeneric<D> {
VariantOne: D,
VariantTwo: (),
}
struct StructWithGeneric<D> {
field_1: D,
field_2: u64,
}
configurable {
BOOL: bool = true,
U8: u8 = 8,
STRUCT: StructWithGeneric<u8> = StructWithGeneric {
field_1: 8,
field_2: 16,
},
ENUM: EnumWithGeneric<bool> = EnumWithGeneric::VariantOne(true),
}
fn main(
switch: bool,
u_8: u8,
some_struct: StructWithGeneric<u8>,
some_enum: EnumWithGeneric<bool>,
) -> bool {
switch == BOOL && u_8 == U8 && some_struct == STRUCT && some_enum == ENUM
}
每个可配置常量在 SDK 中都会获得一个专用的 with
方法。例如,常量 U8
将获得名为 with_U8
的方法,该方法接受 sway 中定义的相同类型。下面是一个示例,其中我们链接了几个 with
方法,并使用新的常量更新了断言。
abigen!(Predicate(
name = "MyPredicate",
abi = "e2e/sway/predicates/predicate_configurables/out/release/predicate_configurables-abi.json"
));
let new_struct = StructWithGeneric {
field_1: 32u8,
field_2: 64,
};
let new_enum = EnumWithGeneric::VariantTwo;
let configurables = MyPredicateConfigurables::default()
.with_U8(8)?
.with_STRUCT(new_struct.clone())?
.with_ENUM(new_enum.clone())?;
let predicate_data =
MyPredicateEncoder::default().encode_data(true, 8u8, new_struct, new_enum)?;
let mut predicate: Predicate = Predicate::load_from(
"sway/predicates/predicate_configurables/out/release/predicate_configurables.bin",
)?
.with_data(predicate_data)
.with_configurables(configurables);