1818from __future__ import annotations
1919
2020import logging
21- import os
2221import textwrap
2322
2423from typing import Union
2827from tabulate import tabulate
2928
3029from ..util import remainder_after , fraction_allocated , commas
31- from ..api import account
3230from .ethereum import Chain , Contract , contract_address # noqa F401
3331
3432__author__ = "Perry Kundert"
3836
3937log = logging .getLogger ( 'multipayout' )
4038
41- goerli_account = None
42- goerli_xprvkey = os .getenv ( 'GOERLI_XPRVKEY' )
43- if not goerli_xprvkey :
44- goerli_seed = os .getenv ( 'GOERLI_SEED' )
45- if goerli_seed :
46- try :
47- # why m/44'/1'? Dunno. That's the derivation path Trezor Suite uses for Goerli wallets...
48- goerli_xprvkey = account ( goerli_seed , crypto = "ETH" , path = "m/44'/1'/0'" ).xprvkey
49- except Exception :
50- pass
51- # Using the "xprv..." key, and derive the 1st sub-account, on the combined path m/44'/1'/0'/0/0
52- goerli_account = account ( goerli_xprvkey , crypto = 'ETH' , path = "m/0/0" )
53-
54-
55- alchemy_urls = dict (
56- Ethereum = 'eth-mainnet.g.alchemy.com/v2' ,
57- Goerli = 'eth-goerli.g.alchemy.com/v2' ,
58- )
59-
60-
61- def alchemy_url ( chain , protocol = 'wss' ):
62- return f"{ protocol } ://{ alchemy_urls [chain .name ]} /{ os .getenv ( 'ALCHEMY_API_TOKEN' )} "
63-
6439
6540def payout_reserve ( addr_frac , bits = 16 ):
6641 """Produce recipients array elements w/ fixed fractional/proportional amounts to predefined
@@ -117,21 +92,32 @@ class MultiPayoutERC20( Contract ):
11792 address, or _deploy a new contract by specifying payees and optionally a list of erc20s to
11893 support.
11994
120- >>> assert os.getenv( 'ETHERSCAN_API_TOKEN' )
121- >>> assert os.getenv( 'ALCHEMY_API_TOKEN' )
122- >>> assert goerli_account
95+ >>> from .ethereum import Chain, alchemy_url
12396 >>> mp = MultiPayoutERC20( Web3.WebsocketProvider( alchemy_url( Chain.Goerli )),
124- ... agent = goerli_account.address,
125- ... agent_prvkey = goerli_account.prvkey,
12697 ... address = "0x8b3D24A120BB486c2B7583601E6c0cf37c9A2C04"
12798 ... )
99+ MultiPayoutERC20 Payees:
100+ | Payee | Share | Frac. % | Reserve | Reserve/2^16 | Frac.Rec. % | Error % |
101+ |--------------------------------------------+-----------------------+-----------+-----------+----------------+---------------+-----------|
102+ | 0x7Fc431B8FC8250A992567E3D7Da20EE68C155109 | 4323/65536 | 6.59638 | 61213 | 61213 | 6.59638 | 0 |
103+ | 0xEeC2b464c2f50706E3364f5893c659edC9E4153A | 1507247699/4294967296 | 35.0933 | 40913 | 40913 | 35.0933 | 0 |
104+ | 0xE5714055437154E812d451aF86239087E0829fA8 | 2504407469/4294967296 | 58.3103 | 0 | 0 | 58.3103 | 0 |
105+ ERC-20s:
106+ | Token | Symbol | Digits |
107+ |--------------------------------------------+----------+----------|
108+ | 0xe802376580c10fE23F027e1E19Ed9D54d4C9311e | USDT | 6 |
109+ | 0xde637d4C445cA2aae8F782FFAc8d2971b93A4998 | USDC | 6 |
110+ | 0xaFF4481D10270F50f203E0763e2597776068CBc5 | WEENUS | 18 |
111+ | 0x1f9061B953bBa0E36BF50F21876132DcF276fC6e | ZEENUS | 0 |
112+
113+ >>> import json
128114 >>> print( json.dumps( mp._payees, indent=4, default=lambda f: f"{float( f * 100 ):9.5f}%" ))
129115 {
130116 "0x7Fc431B8FC8250A992567E3D7Da20EE68C155109": " 6.59637%",
131117 "0xEeC2b464c2f50706E3364f5893c659edC9E4153A": " 35.09335%",
132118 "0xE5714055437154E812d451aF86239087E0829fA8": " 58.31028%"
133119 }
134- >>> print( json.dumps( mp._erc20s , indent=4 ))
120+ >>> print( json.dumps( mp._erc20s_data , indent=4 ))
135121 {
136122 "0xe802376580c10fE23F027e1E19Ed9D54d4C9311e": [
137123 "USDT",
@@ -189,8 +175,7 @@ def __str__( self ):
189175{ self .__class__ .__name__ } Payees:
190176{ textwrap .indent ( self ._payees_table , ' ' * 4 )}
191177ERC-20s:
192- { textwrap .indent ( self ._erc20s_table , ' ' * 4 )}
193- """
178+ { textwrap .indent ( self ._erc20s_table , ' ' * 4 )} """
194179
195180 @property
196181 def _erc20s_table ( self ):
@@ -215,10 +200,7 @@ def _payees_data( self ):
215200 addrs ,fracs ,rsrvs = zip ( * payout_reserve ( self ._payees , bits = self ._bits ))
216201 share = list ( self ._payees [a ] for a in addrs )
217202 rsrvs_int = list ( map ( int , rsrvs ))
218- fracs_recov = list ( fraction_allocated (
219- rsrvs_int ,
220- scale = 2 ** self ._bits ,
221- ))
203+ fracs_recov = list ( fraction_allocated ( rsrvs_int , scale = 2 ** self ._bits ))
222204 # Now, compute the "error" between the originally specified payout fractions, and the payout
223205 # fractions recovered after reversing the 1/2^bits reserve calculations. The error should
224206 # always be < 1/2^bits.
@@ -275,7 +257,6 @@ def _payees_reserve( self, payees_reserve ):
275257 log .warning ( f"Recovered payees fractions don't match: \n { self ._payees_table } " )
276258 else :
277259 self ._payees = payees
278- log .info ( f"Recovered payees fractions from reserves: \n { self ._payees_table } " )
279260
280261 @property
281262 def _payees_table ( self ):
@@ -314,7 +295,6 @@ def _update( self ):
314295
315296 """
316297 self ._forwarder_hash = self .forwarder_hash ()
317- log .info ( f"{ self ._name } Forwarder CREATE2 hash: 0x{ self ._forwarder_hash .hex ()} " )
318298
319299 def payees_reserve ():
320300 for i in count ():
@@ -349,4 +329,4 @@ def erc20s_data():
349329 if self ._erc20s :
350330 assert self ._erc20s == erc20s
351331 else :
352- self ._ers20s = erc20s
332+ self ._erc20s = erc20s
0 commit comments