mirror of
https://github.com/danog/toncontest.git
synced 2024-12-02 09:27:47 +01:00
update
This commit is contained in:
parent
0c96b64bef
commit
49d48352b1
@ -16,3 +16,12 @@ This will automatically build the lite client, fift and func, and will also edit
|
|||||||
* `funcompile` is a wrapper for the `func` compiler, automatically including the stdlib while compiling.
|
* `funcompile` is a wrapper for the `func` compiler, automatically including the stdlib while compiling.
|
||||||
* `fift` is a simple wrapper for the fift compiler.
|
* `fift` is a simple wrapper for the fift compiler.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
* `toolchain` - Some automatic builder scripts and wrappers around the funC compiler and fift
|
||||||
|
* `wallet` - Advanced upgradable multisignature wallet
|
||||||
|
* `test` - A small bugreport about issues with fift exception traces
|
||||||
|
* [GitHub issues and bugreports](https://github.com/ton-blockchain/ton/issues?utf8=%E2%9C%93&q=author%3Adanog+):
|
||||||
|
* [#59, bug in funC compiler](https://github.com/ton-blockchain/ton/issues/59)
|
||||||
|
* [#96, issues with fift exception traces](https://github.com/ton-blockchain/ton/issues/96)
|
||||||
|
* [#87, pull request with more funC dictionary manipulation primitives](https://github.com/ton-blockchain/ton/pull/87)
|
@ -2,6 +2,48 @@
|
|||||||
|
|
||||||
Daniil Gentili's submission (@danogentili, <daniil@daniil.it>).
|
Daniil Gentili's submission (@danogentili, <daniil@daniil.it>).
|
||||||
|
|
||||||
|
Project structure:
|
||||||
|
|
||||||
|
Fift scripts:
|
||||||
|
* `gen-pub.fif` - Generates public/private keypair
|
||||||
|
* `wallet-create.fif` - Creates shared wallet
|
||||||
|
* `wallet-create.fif` - Creates wallet code update request
|
||||||
|
* `create.fif` - Creates simple message to be sent to wallet
|
||||||
|
* `sign.fif` - Adds signature to wallet message
|
||||||
|
* `verify.fif` - Verifies signature of message against known public key
|
||||||
|
* `merge.fif` - Merges multiple messages with same content and different signatures
|
||||||
|
* `inspect.fif` - Inspects the contents of request
|
||||||
|
* `lib.fif` - Library with functions to deserialize and inspect contents of TON messages
|
||||||
|
|
||||||
|
FunC code:
|
||||||
|
* `wallet-code.fc` - Wallet code
|
||||||
|
* `wallet-code-update.fc` - Wallet code with minor change to test wallet code upgrade
|
||||||
|
|
||||||
|
Scripts:
|
||||||
|
* `test.sh` - Creates wallet, set of signed requests and tests wallet in TON VM
|
||||||
|
* `test-update.sh` - Tests wallet code upgrade functionality (after `test.sh`) in TON VM
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
The `test.sh` scripts contains a full set of commands to test every script.
|
||||||
|
```
|
||||||
|
usage: fift -s wallet/wallet-create.fif <workchain-id> <wallet-name> <n> <k> <privkey1> [<pubkey2> ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates a new multisignature wallet in specified workchain composed of <n> (1-10) keys.
|
||||||
|
The first of the keys must be a private key (pre-existing or not), used to generate the wallet; the rest MUST be public keys.
|
||||||
|
|
||||||
|
Min <k> (1-10) signatures required to send an order; load <n> pre-existing public keys from files <key1...n>.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: gen-pub.fif <privkey>
|
||||||
|
```
|
||||||
|
|
||||||
|
Create public key files from private keys; if <privkey> doesn't exist, it will be created.
|
||||||
|
Will also print the hex public key ID.
|
||||||
|
|
||||||
|
* `inspect
|
||||||
Upgradable multisignature wallet.
|
Upgradable multisignature wallet.
|
||||||
Included signature verification scripts to avoid problems with eventual preloaded orders with invalid signatures.
|
Included signature verification scripts to avoid problems with eventual preloaded orders with invalid signatures.
|
||||||
|
|
||||||
|
225
wallet/lib.fif
225
wallet/lib.fif
@ -44,6 +44,99 @@ variable-set sig-count sig-count!
|
|||||||
256 u>B rot 256 u>B -rot ed25519_chksign
|
256 u>B rot 256 u>B -rot ed25519_chksign
|
||||||
} : ed25519_chksignuu
|
} : ed25519_chksignuu
|
||||||
|
|
||||||
|
|
||||||
|
// Inspect multisigwrapper starting from signatures
|
||||||
|
//
|
||||||
|
// multiSigWrapper$_ signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapperStorage X;
|
||||||
|
//
|
||||||
|
// s --
|
||||||
|
{
|
||||||
|
dict@+ swap
|
||||||
|
dup null? abort"Empty signature list!"
|
||||||
|
dup 4 dictlen sig-count!
|
||||||
|
|
||||||
|
."Signed by the following keys: "
|
||||||
|
4 { drop . ."- " -1 } dictforeach cr drop
|
||||||
|
|
||||||
|
."Hash: " dup s>c hashu dup x. cr
|
||||||
|
message-hash!
|
||||||
|
|
||||||
|
// modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
|
||||||
|
// wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
|
||||||
|
|
||||||
|
32 u@+ swap
|
||||||
|
dup ."Expires: " .
|
||||||
|
dup now < { ."(already EXPIRED!)" drop } { ."(in " now - . ."seconds)" } cond cr
|
||||||
|
|
||||||
|
32 u@+ swap
|
||||||
|
."Seqno: " . cr
|
||||||
|
|
||||||
|
1 u@+ swap
|
||||||
|
{
|
||||||
|
."Is code message!" cr
|
||||||
|
// codeMessage$1 minSigs:(## 4) keys:(HashmapE 4 PubKey) code:^Cell = ModeMessage X;
|
||||||
|
|
||||||
|
4 u@+ swap
|
||||||
|
."Minsigs: " . cr
|
||||||
|
|
||||||
|
dict@+ swap
|
||||||
|
dup null? abort"Empty key list!"
|
||||||
|
|
||||||
|
."The following keys are present: " cr
|
||||||
|
4 { swap ."* " . ."- " 32 B@ Bx. cr -1 } dictforeach cr drop
|
||||||
|
|
||||||
|
ref@
|
||||||
|
."Code: " <s csr.
|
||||||
|
}
|
||||||
|
{
|
||||||
|
8 u@+ swap
|
||||||
|
."Mode: " . cr
|
||||||
|
|
||||||
|
// Now on to the actual message we're agreeing to sign
|
||||||
|
//
|
||||||
|
// int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||||
|
// src:MsgAddressInt dest:MsgAddressInt
|
||||||
|
// value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
|
||||||
|
// created_lt:uint64 created_at:uint32 = CommonMsgInfo;
|
||||||
|
// ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
|
||||||
|
// import_fee:Grams = CommonMsgInfo;
|
||||||
|
// ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
|
||||||
|
// created_lt:uint64 created_at:uint32 = CommonMsgInfo;
|
||||||
|
."=>" cr ref@ <s
|
||||||
|
|
||||||
|
1 u@+ swap
|
||||||
|
{ // External message *$1*
|
||||||
|
."Inside: external message" cr
|
||||||
|
}
|
||||||
|
{ // Internal message int_msg_info$0
|
||||||
|
."Inside: internal message" cr
|
||||||
|
1 u@+ swap
|
||||||
|
."Instant hypercube routing disabled? " . cr
|
||||||
|
|
||||||
|
1 u@+ swap
|
||||||
|
."Bounce flag set? " . cr
|
||||||
|
|
||||||
|
1 u@+ swap
|
||||||
|
// ."Bounced flag set? " . cr
|
||||||
|
drop
|
||||||
|
|
||||||
|
2 u@+ nip // Drop src address constructor + flags
|
||||||
|
|
||||||
|
3 u@+ swap // Read dst address constructor + flags
|
||||||
|
// addr_std$10 anycast 0 => 100 => 4
|
||||||
|
4 <> abort"Unsupported address!" // Make things simple for now
|
||||||
|
|
||||||
|
8 i@+
|
||||||
|
256 u@+ -rot
|
||||||
|
."Destination address: " .addr cr
|
||||||
|
|
||||||
|
Gram@+ swap
|
||||||
|
."Grams: " .GR cr
|
||||||
|
} cond
|
||||||
|
drop
|
||||||
|
} cond
|
||||||
|
} : inspect-multisig
|
||||||
|
|
||||||
// Inspects contents of cell provided on top of the stack
|
// Inspects contents of cell provided on top of the stack
|
||||||
// c --
|
// c --
|
||||||
//
|
//
|
||||||
@ -109,75 +202,7 @@ variable-set sig-count sig-count!
|
|||||||
dup ."Message version: " . cr
|
dup ."Message version: " . cr
|
||||||
abort"Unsupported message version!"
|
abort"Unsupported message version!"
|
||||||
|
|
||||||
dict@+ swap
|
inspect-multisig
|
||||||
dup null? abort"Empty signature list!"
|
|
||||||
dup 4 dictlen sig-count!
|
|
||||||
|
|
||||||
."Signed by the following keys: "
|
|
||||||
4 { drop . ."- " -1 } dictforeach cr drop
|
|
||||||
|
|
||||||
."Hash: " dup s>c hashu dup x. cr
|
|
||||||
message-hash!
|
|
||||||
|
|
||||||
// modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
|
|
||||||
// wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
|
|
||||||
|
|
||||||
32 u@+ swap
|
|
||||||
dup ."Expires: " .
|
|
||||||
dup now < { ."(already EXPIRED!)" drop } { ."(in " now - . ."seconds)" } cond cr
|
|
||||||
|
|
||||||
32 u@+ swap
|
|
||||||
."Seqno: " . cr
|
|
||||||
|
|
||||||
1 u@+ swap
|
|
||||||
{ ."Is code message!" cr }
|
|
||||||
{
|
|
||||||
8 u@+ swap
|
|
||||||
."Mode: " . cr
|
|
||||||
|
|
||||||
// Now on to the actual message we're agreeing to sign
|
|
||||||
//
|
|
||||||
// int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
|
||||||
// src:MsgAddressInt dest:MsgAddressInt
|
|
||||||
// value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
|
|
||||||
// created_lt:uint64 created_at:uint32 = CommonMsgInfo;
|
|
||||||
// ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
|
|
||||||
// import_fee:Grams = CommonMsgInfo;
|
|
||||||
// ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
|
|
||||||
// created_lt:uint64 created_at:uint32 = CommonMsgInfo;
|
|
||||||
."=>" cr ref@ <s
|
|
||||||
|
|
||||||
1 u@+ swap
|
|
||||||
{ // External message *$1*
|
|
||||||
."Inside: external message" cr
|
|
||||||
}
|
|
||||||
{ // Internal message int_msg_info$0
|
|
||||||
."Inside: internal message" cr
|
|
||||||
1 u@+ swap
|
|
||||||
."Instant hypercube routing disabled? " . cr
|
|
||||||
|
|
||||||
1 u@+ swap
|
|
||||||
."Bounce flag set? " . cr
|
|
||||||
|
|
||||||
1 u@+ swap
|
|
||||||
// ."Bounced flag set? " . cr
|
|
||||||
drop
|
|
||||||
|
|
||||||
2 u@+ nip // Drop src address constructor + flags
|
|
||||||
|
|
||||||
3 u@+ swap // Read dst address constructor + flags
|
|
||||||
// addr_std$10 anycast 0 => 100 => 4
|
|
||||||
4 <> abort"Unsupported address!" // Make things simple for now
|
|
||||||
|
|
||||||
8 i@+
|
|
||||||
256 u@+ -rot
|
|
||||||
."Destination address: " .addr cr
|
|
||||||
|
|
||||||
Gram@+ swap
|
|
||||||
."Grams: " .GR cr
|
|
||||||
} cond
|
|
||||||
} cond
|
|
||||||
drop
|
|
||||||
} : inspect
|
} : inspect
|
||||||
|
|
||||||
// storage$_ seqno:uint32 minSigs:(## 4) keys:(HashmapE 4 PubKey) messages:(HashmapE 256 (MultiSigWrapperStorage X)) = Storage X;
|
// storage$_ seqno:uint32 minSigs:(## 4) keys:(HashmapE 4 PubKey) messages:(HashmapE 256 (MultiSigWrapperStorage X)) = Storage X;
|
||||||
@ -204,67 +229,7 @@ variable-set sig-count sig-count!
|
|||||||
."Signature count: " dup . cr
|
."Signature count: " dup . cr
|
||||||
sig-count!
|
sig-count!
|
||||||
|
|
||||||
dict@+ swap
|
inspect-multisig
|
||||||
."Signed by the following keys: "
|
|
||||||
4 { drop . ."- " -1 } dictforeach cr drop
|
|
||||||
|
|
||||||
."Hash: " dup s>c hashu dup x. cr
|
|
||||||
message-hash!
|
|
||||||
|
|
||||||
// modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
|
|
||||||
// wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
|
|
||||||
|
|
||||||
32 u@+ swap
|
|
||||||
dup ."Expires: " .
|
|
||||||
dup now < { ."(already EXPIRED!)" drop } { ."(in " now - . ."seconds)" } cond cr
|
|
||||||
|
|
||||||
32 u@+ swap
|
|
||||||
."Seqno: " . cr
|
|
||||||
|
|
||||||
8 u@+ swap
|
|
||||||
."Mode: " . cr
|
|
||||||
|
|
||||||
// Now on to the actual message we're agreeing to sign
|
|
||||||
//
|
|
||||||
// int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
|
||||||
// src:MsgAddressInt dest:MsgAddressInt
|
|
||||||
// value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
|
|
||||||
// created_lt:uint64 created_at:uint32 = CommonMsgInfo;
|
|
||||||
// ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
|
|
||||||
// import_fee:Grams = CommonMsgInfo;
|
|
||||||
// ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
|
|
||||||
// created_lt:uint64 created_at:uint32 = CommonMsgInfo;
|
|
||||||
."=>" cr ref@ <s
|
|
||||||
1 u@+ swap
|
|
||||||
{ // External message *$1*
|
|
||||||
."Inside: external message" cr
|
|
||||||
}
|
|
||||||
{ // Internal message int_msg_info$0
|
|
||||||
."Inside: internal message" cr
|
|
||||||
1 u@+ swap
|
|
||||||
."Instant hypercube routing disabled? " . cr
|
|
||||||
|
|
||||||
1 u@+ swap
|
|
||||||
."Bounce flag set? " . cr
|
|
||||||
|
|
||||||
1 u@+ swap
|
|
||||||
// ."Bounced flag set? " . cr
|
|
||||||
drop
|
|
||||||
|
|
||||||
2 u@+ nip // Drop src address constructor + flags
|
|
||||||
|
|
||||||
3 u@+ swap // Read dst address constructor + flags
|
|
||||||
// addr_std$10 anycast 0 => 100 => 4
|
|
||||||
4 <> abort"Unsupported address!" // Make things simple for now
|
|
||||||
|
|
||||||
8 i@+
|
|
||||||
256 u@+ -rot
|
|
||||||
."Destination address: " .addr cr
|
|
||||||
|
|
||||||
Gram@+ swap
|
|
||||||
."Grams: " .GR cr
|
|
||||||
} cond
|
|
||||||
drop
|
|
||||||
-1
|
-1
|
||||||
} dictforeach drop
|
} dictforeach drop
|
||||||
} : inspect-storage
|
} : inspect-storage
|
@ -10,7 +10,7 @@ signature$_ R:bits256 s:bits256 = Signature;
|
|||||||
// Message + send ModeMessage
|
// Message + send ModeMessage
|
||||||
modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
|
modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
|
||||||
// Special code upgrade message
|
// Special code upgrade message
|
||||||
codeMessage$1 code:^Cell = ModeMessage X;
|
codeMessage$1 minSigs:(## 4) keys:(HashmapE 4 PubKey) code:^Cell = ModeMessage X;
|
||||||
|
|
||||||
// Actual multisigned message
|
// Actual multisigned message
|
||||||
wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
|
wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
|
||||||
|
@ -12,6 +12,7 @@ $# 1- 2 /c const message-count
|
|||||||
variable-set function function!
|
variable-set function function!
|
||||||
variable-set code code!
|
variable-set code code!
|
||||||
variable-set storage storage!
|
variable-set storage storage!
|
||||||
|
variable-set retcode retcode!
|
||||||
|
|
||||||
|
|
||||||
// c7
|
// c7
|
||||||
@ -83,15 +84,18 @@ init-boc <s
|
|||||||
|
|
||||||
."Calling " function . cr cr
|
."Calling " function . cr cr
|
||||||
message-contents function code storage ctx runvmctx .s
|
message-contents function code storage ctx runvmctx .s
|
||||||
swap
|
swap retcode!
|
||||||
."Retcode: " . cr
|
."Retcode: " retcode . cr
|
||||||
dup storage!
|
dup storage!
|
||||||
inspect-storage
|
inspect-storage
|
||||||
|
|
||||||
|
retcode 0 <> abort"Exception"
|
||||||
|
|
||||||
// Manually drop return values of functions
|
// Manually drop return values of functions
|
||||||
function -1 <> {
|
function -1 <> {
|
||||||
2drop
|
2drop
|
||||||
} if
|
} if
|
||||||
|
|
||||||
// rot
|
// rot
|
||||||
// ."Signature: "
|
// ."Signature: "
|
||||||
// 64 B@ Bx.
|
// 64 B@ Bx.
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
#!/bin/bash -e
|
|
||||||
# Define some helper functions
|
|
||||||
chr() { [ "$1" -lt 256 ] || return 1; printf "\\$(printf '%03o' "$1")"; }
|
|
||||||
ord() { LC_CTYPE=C printf '%d' "'$1"; }
|
|
||||||
|
|
||||||
mkdir -p tests
|
|
||||||
cd tests
|
|
||||||
# Create 10 public keys
|
|
||||||
for f in {a..j}; do fift -s ../gen-pub.fif $f;done
|
|
||||||
|
|
||||||
# Create wallet with those 10 public keys on workchain 0, requiring all 10 signatures to send a message
|
|
||||||
fift -s ../wallet-create.fif 0 pony 10 10 {a..j} | tee log
|
|
||||||
|
|
||||||
# Get wallet address
|
|
||||||
address=$(sed '/Bounceable address [(]for later access[)]: /!d;s/.* //g' log)
|
|
||||||
rm log
|
|
||||||
|
|
||||||
# Create a new wallet query signed with key a (ID 0), transferring 10 grams to the wallet itself
|
|
||||||
fift -s ../create.fif pony a 0 $address 0 10 a
|
|
||||||
|
|
||||||
# Sign the query using all keys separately, creating eight more boc files, each signed by two keys only (0 and 1..9)
|
|
||||||
for f in {1..9}; do fift -s ../sign.fif a $(chr $((97+f))) $(chr $((97+f))) $f;done
|
|
||||||
|
|
||||||
# Merge all queries
|
|
||||||
fift -s ../merge.fif {a..j} merge
|
|
||||||
|
|
||||||
# Inspect queries
|
|
||||||
fift -s ../inspect.fif merge
|
|
||||||
|
|
||||||
# Finally run the generated files in the VM
|
|
||||||
#
|
|
||||||
# First init VM with constructor message
|
|
||||||
# Then load first file with only one signature by key a (0)
|
|
||||||
# Run seqno get-method
|
|
||||||
# Run getPartialsByKeyId get-method
|
|
||||||
# Load file with all signatures (and send message)
|
|
||||||
# Run getPartialsByKeyId get-method
|
|
||||||
#
|
|
||||||
fift -s ../test.fif \
|
|
||||||
pony-create \
|
|
||||||
a -1 \
|
|
||||||
0 85143 \
|
|
||||||
0 113609 \
|
|
||||||
merge -1 \
|
|
||||||
0 113609
|
|
@ -112,9 +112,15 @@ int udict_has?(cell dict, int key_len, int index) asm(index dict key_len) "DICTU
|
|||||||
if (storedSignatureCount >= min_sigs) {
|
if (storedSignatureCount >= min_sigs) {
|
||||||
if (message_copy~load_uint(1)) {
|
if (message_copy~load_uint(1)) {
|
||||||
;; Code upgrade
|
;; Code upgrade
|
||||||
|
;; codeMessage$1 minSigs:(## 4) keys:(HashmapE 4 PubKey) code:^Cell = ModeMessage X;
|
||||||
|
;;
|
||||||
|
min_sigs = message_copy~load_uint(4);
|
||||||
|
keys = message_copy~load_dict();
|
||||||
set_code(message_copy~load_ref());
|
set_code(message_copy~load_ref());
|
||||||
} else {
|
} else {
|
||||||
;; Simple message
|
;; Simple message
|
||||||
|
;; modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
|
||||||
|
;;
|
||||||
var (mode, message) = (message_copy~load_uint(8), message_copy~load_ref());
|
var (mode, message) = (message_copy~load_uint(8), message_copy~load_ref());
|
||||||
send_raw_message(message, mode);
|
send_raw_message(message, mode);
|
||||||
}
|
}
|
||||||
@ -209,4 +215,4 @@ int seqno() method_id {
|
|||||||
return (0, begin_cell().end_cell());
|
return (0, begin_cell().end_cell());
|
||||||
}
|
}
|
||||||
return (ok, begin_cell().store_slice(message).end_cell());
|
return (ok, begin_cell().store_slice(message).end_cell());
|
||||||
}
|
}
|
||||||
|
@ -163,17 +163,23 @@ PROGRAM{
|
|||||||
1 LDU
|
1 LDU
|
||||||
SWAP
|
SWAP
|
||||||
IF:<{
|
IF:<{
|
||||||
|
s2 POP
|
||||||
|
s2 POP
|
||||||
|
4 LDU
|
||||||
|
LDDICT
|
||||||
LDREF
|
LDREF
|
||||||
SWAP
|
SWAP
|
||||||
SETCODE
|
SETCODE
|
||||||
|
DUMPSTK
|
||||||
}>ELSE<{
|
}>ELSE<{
|
||||||
8 LDU
|
8 LDU
|
||||||
LDREF
|
LDREF
|
||||||
s0 s2 XCHG
|
s0 s2 XCHG
|
||||||
SENDRAWMSG
|
SENDRAWMSG
|
||||||
|
s3 s3 s0 XCHG3
|
||||||
}>
|
}>
|
||||||
ENDS
|
ENDS
|
||||||
s0 s3 XCHG2
|
s2 s3 XCHG2
|
||||||
8 PUSHPOW2
|
8 PUSHPOW2
|
||||||
DICTUDEL
|
DICTUDEL
|
||||||
DROP
|
DROP
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
."The first of the keys must be a private key (pre-existing or not), used to generate the wallet; the rest MUST be public keys." cr
|
."The first of the keys must be a private key (pre-existing or not), used to generate the wallet; the rest MUST be public keys." cr
|
||||||
."Create or generate public key files from private keys using gen-pub.fif privkey" cr cr
|
."Create or generate public key files from private keys using gen-pub.fif privkey" cr cr
|
||||||
."Min <k> (1-10) signatures required to send an order; load <n> pre-existing public keys from files <key1...n>." cr
|
."Min <k> (1-10) signatures required to send an order; load <n> pre-existing public keys from files <key1...n>." cr
|
||||||
."Optionally load a number of pre-generated partially signed orders <boc1...m> to preload into the contract." cr cr
|
|
||||||
1 halt
|
1 halt
|
||||||
} : usage
|
} : usage
|
||||||
$# 5 < ' usage if
|
$# 5 < ' usage if
|
||||||
@ -56,7 +55,7 @@ rot // Put length on top for times
|
|||||||
|
|
||||||
swap
|
swap
|
||||||
} swap times drop const keys-dict
|
} swap times drop const keys-dict
|
||||||
|
.s
|
||||||
// code
|
// code
|
||||||
"wallet-code.fif" include
|
"wallet-code.fif" include
|
||||||
// data
|
// data
|
||||||
|
Loading…
Reference in New Issue
Block a user