namillum
Version:
Bubble Protocol SDK
395 lines (352 loc) • 10.8 kB
JavaScript
const CODE = `scilla_version 0
(***************************************************)
(* Associated library *)
(***************************************************)
import ListUtils BoolUtils
library MultiSigWallet
let one_msg =
fun (msg : Message) =>
let nil_msg = Nil {Message} in
Cons {Message} msg nil_msg
(* --- gen start --- *)
type MultiSigTransition =
| Mint of (ByStr20) (Uint128)
| Burn of (ByStr20) (Uint128)
| IncreaseAllowance of (ByStr20) (Uint128)
| DecreaseAllowance of (ByStr20) (Uint128)
| Transfer of (ByStr20) (Uint128)
| TransferFrom of (ByStr20) (ByStr20) (Uint128)
let custom_transaction_msg = fun (r: ByStr20) => fun (t: MultiSigTransition) => let msg = match t with
| Mint recipient amount => {
recipient: recipient;
amount: amount;
_tag: "Mint"; _amount: Uint128 0; _recipient: r
}
| Burn burn_account amount => {
burn_account: burn_account;
amount: amount;
_tag: "Burn"; _amount: Uint128 0; _recipient: r
}
| IncreaseAllowance spender amount => {
spender: spender;
amount: amount;
_tag: "IncreaseAllowance"; _amount: Uint128 0; _recipient: r
}
| DecreaseAllowance spender amount => {
spender: spender;
amount: amount;
_tag: "DecreaseAllowance"; _amount: Uint128 0; _recipient: r
}
| Transfer to amount => {
to: to;
amount: amount;
_tag: "Transfer"; _amount: Uint128 0; _recipient: r
}
| TransferFrom from to amount => {
from: from;
to: to;
amount: amount;
_tag: "TransferFrom"; _amount: Uint128 0; _recipient: r
}
end in one_msg msg
(* --- gen end --- *)
let true = True
let zero_uint32 = Uint32 0
let one_uint32 = Uint32 1
type Transaction =
| NativeTransaction of ByStr20 Uint128 String
| CustomTransaction of ByStr20 MultiSigTransition
type Error =
| NotAllowedToSignError
| NotAllowedToExecuteError
| NotAllowedToSubmitError
| TransactionNotFoundError
| SigNotFoundError
| SigFoundError
| NotEnoughSigCountError
| InsufficientFundsError
| InvalidAmountError
| InconsistentSigCountError
let make_error =
fun (result: Error) =>
let result_code =
match result with
| NotAllowedToSignError => Int32 -1
| NotAllowedToExecuteError => Int32 -2
| NotAllowedToSubmitError => Int32 -3
| TransactionNotFoundError => Int32 -4
| SigNotFoundError => Int32 -5
| SigFoundError => Int32 -6
| NotEnoughSigCountError => Int32 -7
| InsufficientFundsError => Int32 -8
| InvalidAmountError => Int32 -9
| InconsistentSigCountError => Int32 -10
end
in
{ _exception: "Error"; code: result_code }
(* Make map of owners *)
let make_owners_map =
fun (owners: List ByStr20) =>
let init = Emp ByStr20 Bool in
let iter =
fun (acc: Map ByStr20 Bool) =>
fun (cur_owner: ByStr20) =>
(* Add owner unconditionally. We check for duplicates later *)
builtin put acc cur_owner true in
let folder = @list_foldl ByStr20 (Map ByStr20 Bool) in
folder iter init owners
contract MultiSigWallet
(
owners_list: List ByStr20,
required_signatures: Uint32,
contract_version: String
)
with
let len = @list_length ByStr20 in
let no_of_owners = len owners_list in
let owners_ok = builtin lt zero_uint32 no_of_owners in
let required_sigs_not_too_low = builtin lt zero_uint32 required_signatures in
let required_sigs_too_high = builtin lt no_of_owners required_signatures in
let required_sigs_not_too_high = negb required_sigs_too_high in
let required_sigs_ok = andb required_sigs_not_too_high required_sigs_not_too_low in
let all_ok = andb required_sigs_ok owners_ok in
(* Building the owners map is expensive, so avoid checking the owners map until *)
(* everything else has been checked *)
match all_ok with
| True =>
let owners_map = make_owners_map owners_list in
let size_of_owners_map = builtin size owners_map in
builtin eq size_of_owners_map no_of_owners
| False =>
False
end
=>
field owners: Map ByStr20 Bool = make_owners_map owners_list
field transaction_count: Uint32 = Uint32 0
field transactions: Map Uint32 Transaction = Emp Uint32 Transaction
field signatures: Map Uint32 (Map ByStr20 Bool) = Emp Uint32 (Map ByStr20 Bool)
field signature_counts: Map Uint32 Uint32 = Emp Uint32 Uint32
procedure Throw(err: Error)
e = make_error err;
throw e
end
procedure AddSignature(transaction_id: Uint32, signee: ByStr20)
has_sig <- exists signatures[transaction_id][signee];
match has_sig with
| True =>
err = SigFoundError;
Throw err
| False =>
maybe_count <- signature_counts[transaction_id];
match maybe_count with
| None =>
(* 0 signatures *)
signature_counts[transaction_id] := one_uint32
| Some count =>
new_count = builtin add count one_uint32;
signature_counts[transaction_id] := new_count
end;
signatures[transaction_id][signee] := true;
e = { _eventname: "AddSignature"; transaction_id: transaction_id };
event e
end
end
procedure SubmitTransaction(transaction: Transaction)
is_owner <- exists owners[_sender];
match is_owner with
| False =>
err = NotAllowedToSubmitError;
Throw err
| True =>
count <- transaction_count;
transactions[count] := transaction;
(* Sender implicitly signs *)
AddSignature count _sender;
new_count = builtin add count one_uint32;
transaction_count := new_count;
e = { _eventname: "SubmitTransaction"; transaction_id: count };
event e
end
end
procedure DeleteTransaction(transaction_id: Uint32)
delete transactions[transaction_id];
delete signatures[transaction_id];
delete signature_counts[transaction_id]
end
procedure ExecuteNativeTransaction(recipient: ByStr20, amount: Uint128, tag: String)
(* Only the recipient or an owner can execute the transaction *)
recipient_is_sender = builtin eq recipient _sender;
is_owner <- exists owners[_sender];
is_allowed = orb recipient_is_sender is_owner;
match is_allowed with
| False =>
err = NotAllowedToExecuteError;
Throw err
| True =>
(* Check for sufficient funds *)
bal <- _balance;
is_not_enough = builtin lt bal amount;
match is_not_enough with
| True =>
err = InsufficientFundsError;
Throw err
| False =>
(* Transaction approved, and enough money available. *)
(* Execute transaction *)
msg = { _tag: tag; _recipient: recipient; _amount: amount };
msgs = one_msg msg;
send msgs
end
end
end
procedure ExecuteCustomTransaction(contract_address: ByStr20, transaction: MultiSigTransition)
(* Only owners may execute *)
is_owner <- exists owners[_sender];
match is_owner with
| False =>
err = NotAllowedToExecuteError;
Throw err
| True =>
msg = custom_transaction_msg contract_address transaction;
send msg
end
end
transition SubmitNativeTransaction(recipient: ByStr20, amount: Uint128, tag: String)
zero_uint128 = Uint128 0;
is_zero = builtin eq amount zero_uint128;
match is_zero with
| True =>
err = InvalidAmountError;
Throw err
| False =>
transaction = NativeTransaction recipient amount tag;
SubmitTransaction transaction
end
end
transition SubmitCustomTransaction(contract_address: ByStr20, transaction: MultiSigTransition)
tx = CustomTransaction contract_address transaction;
SubmitTransaction tx
end
transition SignTransaction(transactionId: Uint32)
(* Only owners are allowed to sign off transactions *)
is_owner <- exists owners[_sender];
match is_owner with
| False =>
err = NotAllowedToSignError;
Throw err
| True =>
(* Transaction must have been submitted *)
has_transaction <- exists transactions[transactionId];
match has_transaction with
| False =>
err = TransactionNotFoundError;
Throw err
| True =>
AddSignature transactionId _sender
end
end
end
transition RevokeSignature(transactionId: Uint32)
has_sig <- exists signatures[transactionId][_sender];
match has_sig with
| False =>
err = SigNotFoundError;
Throw err
| True =>
maybe_count <- signature_counts[transactionId];
match maybe_count with
| None =>
err = InconsistentSigCountError;
Throw err
| Some count =>
is_zero = builtin eq count zero_uint32;
match is_zero with
| True =>
err = InconsistentSigCountError;
Throw err
| False =>
new_count = builtin sub count one_uint32;
signature_counts[transactionId] := new_count;
delete signatures[transactionId][_sender];
e = { _eventname: "RevokeSignature"; transactionId: transactionId };
event e
end
end
end
end
transition ExecuteTransaction(transactionId: Uint32)
maybe_transaction <- transactions[transactionId];
match maybe_transaction with
| None =>
err = TransactionNotFoundError;
Throw err
| Some transaction =>
maybe_sig_count <- signature_counts[transactionId];
match maybe_sig_count with
| None =>
(* Signature count not found, even though the transaction exists. *)
err = InconsistentSigCountError;
Throw err
| Some sig_count =>
not_enough_signatures = builtin lt sig_count required_signatures;
match not_enough_signatures with
| True =>
err = NotEnoughSigCountError;
Throw err
| False =>
match transaction with
| NativeTransaction recipient amount tag =>
ExecuteNativeTransaction recipient amount tag
| CustomTransaction contract_address transaction =>
ExecuteCustomTransaction contract_address transaction
end;
(* Remove transaction and signatures. *)
(* Note: The transaction may have failed, but without a callback *)
(* we have no way of detecting whether it did *)
DeleteTransaction transactionId
end
end
end
end
transition AddFunds()
accept;
e = { _eventname: "AddFunds"; sender: _sender; amount: _amount };
event e
end
transition RecipientAcceptTransfer(
sender : ByStr20,
recipient : ByStr20,
amount : Uint128)
end
transition TransferSuccessCallBack(
sender : ByStr20,
recipient : ByStr20,
amount : Uint128
)
end
transition TransferFromSuccessCallBack(
initiator : ByStr20,
sender : ByStr20,
recipient : ByStr20,
amount : Uint128
)
end
transition RecipientAcceptMint(
minter : ByStr20,
recipient: ByStr20,
amount: Uint128
)
end
transition MintSuccessCallBack(
minter : ByStr20,
recipient : ByStr20,
amount : Uint128
)
end
transition BurnSuccessCallBack(
burner : ByStr20,
burn_account: ByStr20,
amount: Uint128
)
end`;
export default CODE;