Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.

Commit 52a3927

Browse files
committed
[#10] Mostly impl'd multisig example script (minus sigs).
1 parent 2c56b1d commit 52a3927

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed

examples/multisig.py

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# coding=utf-8
2+
"""
3+
Example of how to use PyOTA's multisig feature.
4+
5+
This script will generate a multisig address using private keys from
6+
three different seeds, prepare a bundle, sign the inputs, and then
7+
finally broadcast the transactions to the Tangle.
8+
9+
References:
10+
- https://github.com/iotaledger/wiki/blob/master/multisigs.md
11+
"""
12+
13+
from __future__ import absolute_import, division, print_function, \
14+
unicode_literals
15+
16+
from typing import List
17+
18+
from iota import Address, ProposedTransaction, Tag, TransactionTrytes, \
19+
TryteString
20+
from iota.crypto.types import Digest, Seed
21+
from iota.multisig import MultisigIota
22+
from iota.multisig.types import MultisigAddress
23+
24+
"""
25+
Step 1: Each participant generates one or more digests that will be
26+
used to create the multisig address.
27+
28+
For this example, we will create digests from 3 different private
29+
keys, each owned by a different seed.
30+
31+
Note that this part normally happens on separate computers, so that
32+
participants don't have to share their seeds.
33+
"""
34+
35+
##
36+
# Create digest 1 of 3.
37+
#
38+
# noinspection SpellCheckingInspection
39+
api_1 =\
40+
MultisigIota(
41+
adapter = 'http://localhost:14265',
42+
43+
seed =
44+
Seed(
45+
b'TESTVALUE9DONTUSEINPRODUCTION99999XKMYQP'
46+
b'OIFGQSMIIWCQVMBSOKZASRQOFSIUSSHNDKVL9PJVS',
47+
),
48+
)
49+
50+
gd_result =\
51+
api_1.get_digests(
52+
# Starting key index.
53+
index = 0,
54+
55+
# Number of digests to generate.
56+
count = 1,
57+
58+
# Security level of the resulting digests.
59+
# Must be a value between 1 (faster) and 3 (more secure).
60+
security_level = 3,
61+
)
62+
63+
# ``get_digests`` returns a dict which contains 1 or more digests,
64+
# depending on what value we used for ``count``.
65+
digest_1 = gd_result['digests'][0] # type: Digest
66+
67+
##
68+
# Create digest 2 of 3.
69+
#
70+
# noinspection SpellCheckingInspection
71+
api_2 =\
72+
MultisigIota(
73+
adapter = 'http://localhost:14265',
74+
75+
seed =
76+
Seed(
77+
b'TESTVALUE9DONTUSEINPRODUCTION99999DDWDKI'
78+
b'FFBZVQHHINYDWRSMGGPZUERNLEAYMLFPHRXEWRNST',
79+
),
80+
)
81+
82+
# You can use any starting index that you want.
83+
# For maximum security, each index should be used only once.
84+
gd_result = api_2.get_digests(index=42, count=1, security_level=3)
85+
86+
digest_2 = gd_result['digests'][0] # type: Digest
87+
88+
##
89+
# Create digest 3 of 3.
90+
#
91+
# noinspection SpellCheckingInspection
92+
api_3 =\
93+
MultisigIota(
94+
adapter = 'http://localhost:14265',
95+
96+
seed =
97+
Seed(
98+
b'TESTVALUE9DONTUSEINPRODUCTION99999JYFRTI'
99+
b'WMKVVBAIEIYZDWLUVOYTZBKPKLLUMPDF9PPFLO9KT',
100+
),
101+
)
102+
103+
# It is not necessary for every digest to have the same security level.
104+
gd_result = api_3.get_digests(index=8, count=1, security_level=2)
105+
106+
digest_3 = gd_result['digests'][0] # type: Digest
107+
108+
109+
"""
110+
Step 2: Collect the digests and create a multisig address.
111+
112+
Note that digests are safe to share with other users, so this step is
113+
typically performed on a single instance.
114+
115+
IMPORTANT: Keep track of the order that digests are used; you will
116+
need to ensure that the same order is used to sign inputs!
117+
"""
118+
119+
cma_result =\
120+
api_1.create_multisig_address(digests=[digest_1, digest_2, digest_3])
121+
122+
# For consistency, every API command returns a dict, even if it only
123+
# has a single value.
124+
multisig_address = cma_result['address'] # type: MultisigAddress
125+
126+
127+
"""
128+
Step 3: Prepare the bundle.
129+
130+
This step occurs some time later, after the multisig address has
131+
received some IOTAs.
132+
133+
IMPORTANT: In IOTA, it is unsafe to spend from a single address
134+
multiple times. Take care to spend ALL of the IOTAs controlled by the
135+
multisig address, or generate a new multisig address that will receive
136+
the change from the transaction!
137+
"""
138+
139+
# noinspection SpellCheckingInspection
140+
pmt_result =\
141+
api_1.prepare_multisig_transfer(
142+
# These are the transactions that will spend the IOTAs.
143+
# You can divide up the IOTAs to send to multiple addresses if you
144+
# want, but to keep this example focused, we will only include a
145+
# single spend transaction.
146+
transfers = [
147+
ProposedTransaction(
148+
address =
149+
Address(
150+
b'TESTVALUE9DONTUSEINPRODUCTION99999NDGYBC'
151+
b'QZJFGGWZ9GBQFKDOLWMVILARZRHJMSYFZETZTHTZR',
152+
),
153+
154+
value = 42,
155+
156+
# If you'd like, you may include an optional tag and/or
157+
# message.
158+
tag = Tag(b'KITTEHS'),
159+
message = TryteString.from_string('thanx fur cheezburgers'),
160+
),
161+
],
162+
163+
# Specify our multisig address as the input for the spend
164+
# transaction(s).
165+
# Note that PyOTA currently only allows one multisig input per
166+
# bundle (although the protocol does not impose a limit).
167+
multisig_input = multisig_address,
168+
169+
# If there will be change from this transaction, you MUST specify
170+
# the change address! Unlike regular transfers, multisig transfers
171+
# will NOT automatically generate a change address; that wouldn't
172+
# be fair to the other participants!
173+
change_address = None,
174+
)
175+
176+
prepared_trytes = pmt_result['trytes'] # type: List[TransactionTrytes]
177+
178+
179+
"""
180+
Step 4: Sign the inputs.
181+
182+
Note that we must apply signatures in the same order as when we created
183+
the multisig address!
184+
"""
185+
# :todo:
186+
signed_trytes = None # type: List[TransactionTrytes]
187+
188+
189+
"""
190+
Step 5: Broadcast the bundle.
191+
192+
Note that this step works the same as any other transfer.
193+
"""
194+
api_1.send_trytes(trytes=signed_trytes, depth=3)

0 commit comments

Comments
 (0)