Skip to content

Commit f7779b5

Browse files
committed
Document scanning for, loading and deploying MultiPayoutERC20
1 parent 01c76b9 commit f7779b5

File tree

8 files changed

+381
-217
lines changed

8 files changed

+381
-217
lines changed

GNUmakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ test:
7878

7979
analyze:
8080
$(PY3) -m flake8 --color never -j 1 --max-line-length=250 \
81+
--exclude slip39/tabulate \
8182
--ignore=W503,E201,E202,E203,E127,E221,E223,E226,E231,E241,E242,E251,E265,E272,E274 \
8283
slip39
8384

README.org

Lines changed: 349 additions & 196 deletions
Large diffs are not rendered by default.

README.pdf

19 KB
Binary file not shown.

images/BIP-39-backup-entropy.png

100 Bytes
Loading

slip39/generator/main.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def main( argv=None ):
206206
healthy = serial_connected
207207
encoding = 'UTF-8'
208208

209-
def file_opener():
209+
def file_opener(): # noqa: F811
210210
ser = Serial(
211211
port = args.device,
212212
baudrate = args.baudrate or BAUDRATE,
@@ -217,7 +217,7 @@ def file_opener():
217217
)
218218
return ser
219219

220-
def healthy_reset( file ):
220+
def healthy_reset( file ): # noaq: F811
221221
file.dtr = False
222222
# Wait for a server to de-assert DTR, discarding input. After the Server has de-asserted, we still need to drain
223223
# the Server's output / Client's input buffers, so keep flushing 'til input buffer empty...
@@ -346,7 +346,7 @@ def healthy_reset( file ):
346346
encoding = 'UTF-8'
347347
healthy = serial_connected
348348

349-
def file_opener():
349+
def file_opener(): # noqa: F811
350350
ser = Serial(
351351
port = args.device,
352352
baudrate = args.baudrate or BAUDRATE,
@@ -356,7 +356,7 @@ def file_opener():
356356
)
357357
return ser
358358

359-
def healthy_waiter( file ):
359+
def healthy_waiter( file ): # noqa: F811
360360
file.dtr = False
361361
# Wait for a client; when seen, assert DTR
362362
while ( flow := serial_flow( file ) ) and not flow[0].dsr:

slip39/invoice/ethereum.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def etherscan( chain, params, headers=None, apikey=None, timeout=None, verify=Tr
228228
return response_json['result']
229229

230230

231-
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.WARNING, exc_at=logging.WARNING, default_cls=dict )
231+
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.INFO, exc_at=logging.WARNING, default_cls=dict )
232232
def gasoracle( chain=None, **kwds ):
233233
"""Return (possibly cached) Gas Oracle values from etherscan.io, or empty dict, allowing retries w/
234234
up to 3*1.5^5 seconds (22s) exponential backoff.
@@ -244,7 +244,7 @@ def gasoracle( chain=None, **kwds ):
244244
)
245245

246246

247-
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.WARNING, exc_at=logging.WARNING, default_cls=dict )
247+
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.INFO, exc_at=logging.WARNING, default_cls=dict )
248248
def ethprice( chain=None, **kwds ):
249249
"""Return (possibly cached) Ethereum price in $USD from etherscan.io, or empty dict (performs exponential
250250
backoff of 3*1.5^5 seconds (22s) on Exceptions.)
@@ -260,7 +260,7 @@ def ethprice( chain=None, **kwds ):
260260
)
261261

262262

263-
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.WARNING, exc_at=logging.WARNING, default_cls=dict )
263+
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.INFO, exc_at=logging.WARNING, default_cls=dict )
264264
def erc20tx( chain=None, address=None, token=None, **kwds ):
265265
"""Return (possibly cached) ERC-20 transactions from etherscan.io, or empty dict (performs exponential
266266
backoff of 3*1.5^5 seconds (22s) on Exceptions.)
@@ -293,7 +293,7 @@ def erc20tx( chain=None, address=None, token=None, **kwds ):
293293
)
294294

295295

296-
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.WARNING, exc_at=logging.WARNING, default_cls=dict )
296+
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.INFO, exc_at=logging.WARNING, default_cls=dict )
297297
def etherbalance( chain=None, address=None, **kwds ):
298298
"""Return (possibly cached) ETH balance from etherscan.io, or empty dict (performs exponential
299299
backoff of 3^5 seconds (4 min.) on Exceptions.)
@@ -315,7 +315,7 @@ def etherbalance( chain=None, address=None, **kwds ):
315315
)
316316

317317

318-
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.WARNING, exc_at=logging.WARNING, default_cls=dict )
318+
@retry( tries=5, delay=3, backoff=1.5, log_at=logging.INFO, exc_at=logging.WARNING, default_cls=dict )
319319
def ethertx( chain=None, address=None, **kwds ):
320320
"""Return (possibly cached) ETH normal transactions from etherscan.io, or empty dict (performs exponential
321321
backoff of 3^5 seconds (4 min.) on Exceptions.)
@@ -355,7 +355,7 @@ def etherio( chain=None, address=None, direction=None, **kwds ):
355355
"""
356356
if direction is None:
357357
direction = Direction.Incoming
358-
for tx in ethertx( chain=chain, address=address ):
358+
for tx in ethertx( chain=chain, address=address, **kwds ):
359359
if tx["value"] == "0" or tx["isError"] != "0":
360360
continue
361361
# A non-error value-bearing transaction. Ignore?
@@ -830,7 +830,7 @@ def _call( self, name, *args, gas=None, **kwds ):
830830
success = False
831831
raise
832832
finally:
833-
log.warning( f"Called {self._name}.{name}( {commas( args )} ) -{'-' if success else 'x'}> {result}" )
833+
log.info( f"Called {self._name}.{name}( {commas( args )} ) -{'-' if success else 'x'}> {result}" )
834834
return result
835835

836836
def __getattr__( self, name ):
@@ -993,7 +993,7 @@ def _deploy( self, *args, gas=None, **kwds ):
993993
beg = timer()
994994
while ( block_number := self._w3.eth.block_number ) < cons_receipt.blockNumber:
995995
time.sleep( 1 )
996-
log.warning( f"Waited {timer()-beg:.2f}s for block {block_number} to be mined, vs. Contract block: {cons_receipt.blockNumber}" )
996+
log.info( f"Waited {timer()-beg:.2f}s for block {block_number} to be mined, vs. Contract block: {cons_receipt.blockNumber}" )
997997

998998
self._update()
999999

slip39/invoice/multipayout_test.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,6 @@ def test_multipayout_ERC20_web3_tester( testnet, provider, chain_id, src, src_pr
431431
latest = w3.eth.get_block('latest')
432432
print( f"{testnet:10}: Web3 Latest block: {json.dumps( latest, indent=4, default=str )}" )
433433

434-
435434
def gas_pricing(
436435
of = f"{testnet:10}: Web3 Tester",
437436
gas = None,
@@ -566,7 +565,7 @@ def gas_pricing(
566565

567566
MultiPayoutERC20_contract = w3.eth.contract( abi=mp_ERC20_abi, bytecode=mp_ERC20_bytecode )
568567

569-
gas = 1400000 # 1388019 Gas is actual cost, as of 20230910
568+
gas = 1400000 # 1388019 Gas is actual cost, as of 20230910
570569
spend = gas * max_usd_per_gas
571570
gas_price = ETH.maxPriorityFeePerGas( spend=spend, gas=gas ) if ETH.UPDATED else gas_price_testnet
572571
mc_cons_tx = {
@@ -576,10 +575,10 @@ def gas_pricing(
576575
} | gas_price
577576

578577
gas_pricing( f"{testnet:10}: Web3 Tester Construct MultiPayoutERC20", **mc_cons_tx)
579-
578+
580579
print( f"{testnet:10}: Web3 Tester Construct MultiPayoutERC20 Tx (using {'Mainnet' if ETH.UPDATED else 'Testnet'} Gas pricing): {json.dumps(mc_cons_tx, indent=4)}" )
581580
# Let's see what this would cost, using the estimated gas:
582-
581+
583582
mc_cons_hash = MultiPayoutERC20_contract.constructor( payees, tokens ).transact( mc_cons_tx )
584583
print( f"{testnet:10}: Web3 Tester Construct MultiPayoutERC20 hash: {mc_cons_hash.hex()}" )
585584
mc_cons = w3.eth.get_transaction( mc_cons_hash )
@@ -1089,11 +1088,23 @@ def test_multipayout_recover( testnet, provider, chain_id, src, src_prvkey, dest
10891088
# Recover an already deployed MultiPayoutERC20. No need for a GasOracle (free calls only)
10901089
mp_r = MultiPayoutERC20(
10911090
provider,
1092-
address = "0xb8A8db0B4B8107c71D0C079351Be69c8CCe27469",
1093-
agent = src,
1094-
agent_prvkey = src_prvkey,
1091+
address = "0xdb0bFb2E582Ecd3bc51C264d2F087D034857bF40",
10951092
)
1096-
print( f"Recovered MultiPayoutERC20 at {mp_r._address}" )
1093+
print( f"Recovered MultiPayoutERC20 at {mp_r._address}: {mp_r}" )
1094+
assert str(mp_r) == """\
1095+
MultiPayoutERC20 Payees:
1096+
| Payee | Share | Frac. % | Reserve | Reserve/2^16 | Frac.Rec. % | Error % |
1097+
|--------------------------------------------+-----------------------+-----------+-----------+----------------+---------------+-----------|
1098+
| 0xEeC2b464c2f50706E3364f5893c659edC9E4153A | 14979/65536 | 22.8561 | 50557 | 50557 | 22.8561 | 0 |
1099+
| 0xE5714055437154E812d451aF86239087E0829fA8 | 1228888999/4294967296 | 28.6123 | 41229 | 41229 | 28.6123 | 0 |
1100+
| 0x7Fc431B8FC8250A992567E3D7Da20EE68C155109 | 2084414553/4294967296 | 48.5316 | 0 | 0 | 48.5316 | 0 |
1101+
ERC-20s:
1102+
| Token | Symbol | Digits |
1103+
|--------------------------------------------+----------+----------|
1104+
| 0xe802376580c10fE23F027e1E19Ed9D54d4C9311e | USDT | 6 |
1105+
| 0xde637d4C445cA2aae8F782FFAc8d2971b93A4998 | USDC | 6 |
1106+
| 0xaFF4481D10270F50f203E0763e2597776068CBc5 | WEENUS | 18 |
1107+
| 0x1f9061B953bBa0E36BF50F21876132DcF276fC6e | ZEENUS | 0 |"""
10971108

10981109

10991110
@pytest.mark.skipif( not goerli_xprvkey and not ganache_xprvkey,

slip39/invoice/payments_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import pytest
22
import logging
3-
import os
43
import subprocess
54

65
from pathlib import Path

0 commit comments

Comments
 (0)