/*
* ESCROW WITH DELAY
*
* An escrow agent can approve the movement of coins in cooperation with the
* sender or the recipient. The escrow agent cannot steal the coins for himself.
* The sender can refund her coins after a timeout.
*
* https://docs.ivylang.org/bitcoin/language/ExampleContracts.html#escrowwithdelay
*/
fn not(bit: bool) -> bool {
<u1>::into(jet::complement_1(<bool>::into(bit)))
}
fn checksig(pk: Pubkey, sig: Signature) {
let msg: u256 = jet::sig_all_hash();
jet::bip_0340_verify((pk, msg), sig);
}
fn checksig_add(counter: u8, pk: Pubkey, maybe_sig: Option<Signature>) -> u8 {
match maybe_sig {
Some(sig: Signature) => {
checksig(pk, sig);
let (carry, new_counter): (bool, u8) = jet::increment_8(counter);
assert!(not(carry));
new_counter
}
None => counter,
}
}
fn check2of3multisig(pks: [Pubkey; 3], maybe_sigs: [Option<Signature>; 3]) {
let [pk1, pk2, pk3]: [Pubkey; 3] = pks;
let [sig1, sig2, sig3]: [Option<Signature>; 3] = maybe_sigs;
let counter1: u8 = checksig_add(0, pk1, sig1);
let counter2: u8 = checksig_add(counter1, pk2, sig2);
let counter3: u8 = checksig_add(counter2, pk3, sig3);
let threshold: u8 = 2;
assert!(jet::eq_8(counter3, threshold));
}
fn transfer_spend(maybe_sigs: [Option<Signature>; 3]) {
let sender_pk: Pubkey = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798; // 1 * G
let recipient_pk: Pubkey = 0xc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5; // 2 * G
let escrow_pk: Pubkey = 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9; // 3 * G
check2of3multisig([sender_pk, recipient_pk, escrow_pk], maybe_sigs);
}
fn timeout_spend(sender_sig: Signature) {
let sender_pk: Pubkey = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798; // 1 * G
checksig(sender_pk, sender_sig);
let timeout: Distance = 1000;
jet::check_lock_distance(timeout);
}
fn main() {
match witness::TRANSFER_OR_TIMEOUT {
Left(maybe_sigs: [Option<Signature>; 3]) => transfer_spend(maybe_sigs),
Right(sender_sig: Signature) => timeout_spend(sender_sig),
}
}