---
# System prepended metadata

title: SC

---

# SC
```c
;; Constants:
;; CANCEL_CODE = 0x01;
;; START_CODE = 0x02;
;; FAST_EXIT_CODE = 0x03;
;; SEND_STATE_CODE = 0x04;
;; SEND_SIG_CODE = 0x05;
;; SEND_PAYADDR_CODE = 0x06;

(int, int, int, int, int, int, int, int, int) get_contract_state() {
     var ds = get_data().begin_parse();
     
     var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = (
            ds~load_uint(1),
            ds~load_uint(32),
            ds~load_uint(48),
            ds~load_uint(256),
            ds~load_uint(256),
            ds~load_uint(1),
            ds~load_uint(1),
            ds~load_uint(214),
            ds~load_uint(214)
     );

     ds.end_parse();

     return (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb);
}

() set_contract_state(int init, int timeout, int timestamp, int pubA, int pubB, int lockA, int lockB, int Xa, int Xb) {
     var ds = begin_cell()
        .store_uint(init, 1)         ;; init        1 bit flag to initialize contract
        .store_uint(timeout, 32)     ;; timeout     32 bits timeout in second for exit
        .store_uint(timestamp, 48)   ;; timestamp   48 bits unix time in seconds
        .store_uint(pubA, 256)       ;; pubA        256 bits    pub key of user A
        .store_uint(pubB, 256)       ;; pubB        256 bits    pub key of user B
        .store_uint(lockA, 1)        ;; lockA       1 bit   flag registry for A
        .store_uint(lockB, 1)        ;; lockB       1 bit   flag registry for B
        .store_uint(Xa, 214)         ;; Xa - amount that first user is going to send
        .store_uint(Xb, 214)         ;; Xb - amount that second user is going to send
        .end_cell();

    set_data(ds);
}

() send_grams(int dest_addr, int amount) {
    
    send_raw_message(begin_cell()
        .store_uint(0xc400, 17)
        .store_uint(dest_addr, 256)
        .store_grams(amount)
        .store_uint(0, 106)
        .store_uint(0x444f4e45, 33)
        .end_cell(), 3);
}

(int) get_balance() {
    return 0;
}

;; deposit funds during initialization
() deposit(int pubkey, int msg_value) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(1, init == 0);

    if (pubkey == pubA) {
        Xa += msg_value;
    } elseif (pubkey == pubB) {
        Xb += msg_value;
    } else {
        throw(2);
    }
}


;; withdraw funds before payment channel started
() cancel(slice signature) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(1, init == 0);
    
    var checking_slice = begin_cell()
         .store_uint(0x01, 4)
         .store_slice(my_address())
         .end_cell();

    var data_slice_hash = slice_hash(checking_slice.begin_parse());

    throw_unless(201, check_signature(data_slice_hash, signature, pubA) | check_signature(data_slice_hash, signature, pubB));

    accept_message();

    init = 1;
    send_grams(Xa, pubA);
    send_grams(Xb, pubB);
    Xa = 0;
    Xb = 0;
    set_contract_state(init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb);
}

;; finish initialization and start the channel
() start(slice sig_a, slice sig_b, int Ua, int Ub) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(1, init == 0);
    
    var checking_slice = begin_cell()
         .store_uint(0x02, 4)
         .store_slice(my_address())
         .store_uint(Ua, 214)
         .store_uint(Ub, 214)
         .end_cell();
         
    var data_slice_hash = slice_hash(checking_slice.begin_parse());  
    
    throw_unless(202, check_signature(data_slice_hash, sig_a, pubA));
    throw_unless(203, check_signature(data_slice_hash, sig_b, pubB));

    if ((Xa < Ua) | (Xb < Ub)) {
        throw(5);
    }

    accept_message();

    if (Xa > Ua) {
        send_grams(pubA, Ua - Xa);
    }

    if (Xb > Ub) {
        send_grams(pubB, Ub - Xb);
    }

    Xa = 0;
    Xb = 0;
    init = 1;
    set_contract_state(init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb);
}

;; exit with no delay if both parties signed the exit message
() fast_exit(int _amountA, slice sig_a, slice sig_b) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(1, init == 1);
    
    var checking_slice = begin_cell()
         .store_uint(0x03, 4)
         .store_slice(my_address())
         .store_uint(_amountA, 214)
         .end_cell();
         
         
    var data_slice_hash = slice_hash(checking_slice.begin_parse());
     
    throw_unless(204, check_signature(data_slice_hash, sig_a, pubA));
    throw_unless(205, check_signature(data_slice_hash, sig_b, pubB));

    accept_message();

    var amountA = min(_amountA, get_balance());
    var amountB = get_balance() - amountA;

    send_grams(amountA, pubA);
    send_grams(amountB, pubB);
}

;; initialize a withdraw and start challenge period
() send_state(slice sig_a, int _Xa, slice sig_b, int _Xb, slice sig_sender) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(7, init == 1);
    throw_if(8, get_balance() == 0);
    
    var checking_slice_a = begin_cell()
         .store_uint(0x04, 4)
         .store_slice(my_address())
         .store_uint(_Xa, 214)
         .end_cell();
        
    var checking_slice_b = begin_cell()
         .store_uint(0x04, 4)
         .store_slice(my_address())
         .store_uint(_Xb, 214)
         .end_cell();
    
    var checking_slice_a_b = begin_cell()
         .store_uint(0x04, 4)
         .store_slice(my_address())
         .store_uint(_Xa, 214)
         .store_uint(_Xb, 214)
         .end_cell();
         
         
    var data_slice_hash_a = slice_hash(checking_slice_a.begin_parse());
    var data_slice_hash_b = slice_hash(checking_slice_b.begin_parse());    
    var data_slice_hash_a_b = slice_hash(checking_slice_a_b.begin_parse()); 
    
    throw_unless(206, check_signature(data_slice_hash_a, sig_a, pubA));
    throw_unless(207, check_signature(data_slice_hash_b, sig_b, pubB));
         
    var senderA = 0;
    
    if (check_signature(data_slice_hash_a_b, sig_sender, pubA)) {
        senderA = 0x1;
    } elseif (check_signature(data_slice_hash_a_b, sig_sender, pubB)) {
        senderA = 0x0;
    } else {
        throw(10);
    }

    accept_message();

    if (timestamp == 0) {
        timestamp = now() + timeout;
    }

    if((lockA == 0) & (Xa < _Xa)) {
        Xa = _Xa;
        if (senderA == false) {
            lockA = 1;
        }
    }

    if((lockB == 0) & (Xb < _Xb)) {
        Xb = _Xb;
        if (senderA) {
            lockB = 1;
        }
    }
    
    set_contract_state(init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb);
}


;; exit by timeout
() finalize(slice sig_a, int addrA, slice sig_b, int addrB) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(11, init == 1);
    throw_if(12, timestamp < now() & ((lockA & lockB) == false));

    var checking_slice_a = begin_cell()
         .store_uint(0x06, 4)
         .store_slice(my_address())
         .store_uint(addrA, 256)
         .end_cell();

    var checking_slice_b = begin_cell()
         .store_uint(0x06, 4)
         .store_slice(my_address())
         .store_uint(addrB, 256)
         .end_cell();
         
    var data_slice_hash_a = slice_hash(checking_slice_a.begin_parse());
    var data_slice_hash_b = slice_hash(checking_slice_b.begin_parse());    
    
    throw_unless(207, check_signature(data_slice_hash_a, sig_a, pubA));
    throw_unless(208, check_signature(data_slice_hash_b, sig_b, pubB));

    accept_message();

    var a = Xa - Xb + get_balance() / 2;
    var b = get_balance() - a;
    if (a < 0) {
        a = 0;
    }
    if (a > get_balance()) {
        a = get_balance();
    }

    send_grams(pubA, a);
    send_grams(pubB, b);
}

() challenge(slice signature, int X) {
    var (init, timeout, timestamp, pubA, pubB, lockA, lockB, Xa, Xb) = get_contract_state();
    throw_unless(13, init == 1);
    throw_if(14, get_balance() == 0);
    
    accept_message();
    
    var checking_slice = begin_cell()
         .store_uint(0x05, 4)
         .store_slice(my_address())
         .store_uint(X, 214)
         .end_cell();
         
    var data_slice_hash = slice_hash(checking_slice.begin_parse());
    
    if (check_signature(data_slice_hash, signature, pubA)) {
        if ((X > Xa) & lockA & (lockB == false)) {
            ;; send_grams(pubB, get_balance());
            Xb = get_balance() / 2;
            Xa = 0;
            lockB = 1;
        }
    } elseif (check_signature(data_slice_hash, signature, pubB)) {
        if ((X > Xb) & lockB & (lockA == false)) {
            ;; send_grams(pubA, get_balance());
            Xa = 0;
            Xb = get_balance() / 2;
            flagA = 1;
        }
    } else {
        throw(15);
    }
}

() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
  ;; probably standard transfers have different serialization format
  var cs = in_msg_cell.begin_parse();
  var pubkey = cs~load_uint(256);
  deposit(pubkey, msg_value);
  cs.end_parse();
}
;; 0x4e43ef05 -> "() change_elector_code(slice cs)"
() recv_external(slice in_msg) impure {
    var cs = in_msg;
    ;; tag = hash(method_name)[0:4]
    var tag = cs~load_uint(4);
    if (tag == 0x00000000) {
        var signature = cs~load_bits(512);
        cs.end_parse();
        cancel(signature);
    } elseif (tag == 0x00000001) {
        var sig_a = cs~load_bits(512);
        var Ua = cs~load_uint(214);
        var sig_b = cs~load_bits(512);
        var Ub = cs~load_uint(214);
        cs.end_parse();
        start(sig_a, sig_b, Ua, Ub);
    } elseif (tag == 0x00000002) {
        var _amountA = cs~load_uint(214);
        var sig_a = cs~load_bits(512);
        var sig_b = cs~load_bits(512);
        cs.end_parse();
        fast_exit(_amountA, sig_a, sig_b);
    } elseif (tag == 0x00000003) {
        var sig_a = cs~load_bits(512);
        var _Xa = cs~load_uint(214);
        var sig_b = cs~load_bits(512);
        var _Xb = cs~load_uint(214);
        var sender_sig = cs~load_bits(512);
        cs.end_parse();
        send_state(sig_a, _Xa, sig_b, _Xb, sender_sig);
    } elseif (tag == 0x00000004) {
        var signature = cs~load_bits(512);
        var X = cs~load_uint(214);
        cs.end_parse();
        challenge(signature, X);
    }
}
```