44 Commits

Author SHA1 Message Date
Carlosokumu
2055038c80 update deployed voucher list 2024-12-18 08:52:57 +03:00
Carlosokumu
679d92ae4d update deployed voucher list 2024-12-18 07:53:04 +03:00
Carlosokumu
8abbf2f938 add list of already deployed vouchers 2024-12-18 07:30:53 +03:00
Carlosokumu
c3bcd54ed7 add voucher create 2024-12-18 07:30:21 +03:00
Carlosokumu
e79665190a generate 3 random chars instead of two 2024-12-18 07:29:57 +03:00
Carlosokumu
8bc9f5619c chore: remove voucher list 2024-12-16 10:55:15 +03:00
Carlosokumu
b32d776183 add default env vars,use actual voucher decimal 2024-12-16 09:48:47 +03:00
Carlosokumu
db815494d3 downgrade web3 version 2024-12-15 21:07:08 +03:00
Carlosokumu
682836fa1e add nonce parameter 2024-12-15 12:37:33 +03:00
Carlosokumu
1ea883ae54 add voucher list 2024-12-15 12:36:52 +03:00
Carlosokumu
4a4eb0f077 update seed commands 2024-12-15 12:36:39 +03:00
Carlosokumu
885271ce69 add sample custodial seed commands 2024-12-13 15:03:35 +03:00
Carlosokumu
b586273f70 add sample deployed vouchers 2024-12-13 14:58:02 +03:00
Carlosokumu
3a9a123648 add bearer token example 2024-12-12 14:04:32 +03:00
Carlosokumu
01d7de89c2 add explit nonce value to cast commands 2024-12-12 14:02:27 +03:00
Carlosokumu
7b9bff6541 add transfer to custodial accounts 2024-12-11 17:46:38 +03:00
Carlosokumu
2f0b59e579 fix parser error 2024-12-10 15:55:12 +03:00
Carlosokumu
e5ed224c72 wait for process to finish before next execution 2024-12-09 10:09:57 +03:00
Carlosokumu
e530925d9c update example env 2024-12-06 15:12:50 +03:00
Carlosokumu
1bbf26ceb1 add sleep after each execution 2024-12-06 15:08:51 +03:00
Carlosokumu
c5ff6f3bf1 update sample commands 2024-12-06 15:07:23 +03:00
Carlosokumu
d1a794fe37 update handlers: add thread sleep to allow token registration 2024-12-06 14:08:43 +03:00
Carlosokumu
9aaa125948 add command to add token to token index 2024-12-06 10:23:19 +03:00
Carlosokumu
78fc736ed7 update handlers: append new vouchers to json store 2024-12-05 17:57:32 +03:00
Carlosokumu
dc87181e0a parse json from ge-publish 2024-11-30 11:46:55 +03:00
Carlosokumu
a5e84ba7df add json flag to cast commands 2024-11-29 14:31:47 +03:00
Carlosokumu
dece337480 add seed commands 2024-11-29 14:02:09 +03:00
Carlosokumu
3e42f10625 Merge branch 'lash/mux-input' into v-seed-test 2024-11-28 15:50:14 +03:00
lash
e343ee8bae Allow two labels in voucher transfer 2024-11-28 12:37:24 +00:00
Carlosokumu
24172aa4b5 update handlers 2024-11-27 15:30:47 +03:00
Carlosokumu
71d157a482 raise error on invalid input 2024-11-26 14:42:33 +03:00
Carlosokumu
4da0e5812f use same private key for minting 2024-11-26 13:30:52 +03:00
Carlosokumu
9b513b672d update commands 2024-11-26 13:08:02 +03:00
Carlosokumu
f6c0e2de04 update handlers 2024-11-26 10:05:11 +03:00
Carlosokumu
541d083fc7 update commands 2024-11-26 10:04:26 +03:00
Carlosokumu
2bfc1ce3b2 update commands 2024-11-25 12:38:18 +03:00
Carlosokumu
5061aace41 update handler 2024-11-25 12:37:52 +03:00
Carlosokumu
a043f33242 update handlers 2024-11-25 11:39:12 +03:00
Carlosokumu
d1a4f2ee5d add example env file 2024-11-23 13:26:01 +03:00
Carlosokumu
083e3e6b69 add commands 2024-11-23 13:23:42 +03:00
Carlosokumu
baf21fca96 update handlers 2024-11-23 13:23:16 +03:00
Carlosokumu
a3d149a659 add handlers 2024-11-19 19:03:58 +03:00
lash
f25d45af4c Merge branch 'master' into lash/mux-input 2024-11-07 13:16:55 +00:00
lash
fa64acac1d WIP mux prompt and socket input 2024-10-28 00:45:07 +00:00
5 changed files with 755 additions and 106 deletions

17
.env.example Normal file
View File

@@ -0,0 +1,17 @@
#Chain params
CHAIN_ID = 44787
RPC = https://alfajores-forno.celo-testnet.org
GAS_FEE_CAP = 35000000000
#Amount of gas to topup each generated account
GAS_TOPUP = "0.01ether"
#address to token index
TOKEN_INDEX = 0xD774bc082003eaF8DF74eEcD43AD44F03D488418
#Private key with the required permissions
MASTER_PRIVATE_KEY = 1e1d0c1519479f68d9
#Token required to perform custodial api calls
BEARER_TOKEN=eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9

View File

@@ -0,0 +1,13 @@
VOUCHER_CREATE - MIA MIAPESA 6
VOUCHER_CREATE - MES MAASAIPESA 6
VOUCHER_CREATE - KMP KAMBAPESA 6
KEY_CREATE - mijikenda custodialstore
KEY_CREATE - kamba custodialstore
KEY_CREATE - maasai custodialstore
KEY_CREATE - agiriama custodialstore
VOUCHER_MINT - MIA 100000000 mijikenda
VOUCHER_MINT - MES 100000000 maasai
VOUCHER_MINT - KMP 100000000 kamba
VOUCHER_TRANSFER - MIA 2000000 kamba mijikenda
VOUCHER_TRANSFER - MES 2000000 mijikenda maasai
VOUCHER_TRANSFER - KMP 2000000 mijikenda kamba

794
parse.py
View File

@@ -1,73 +1,131 @@
import json
import random
import re
import string
import time
import ply.lex as lex
import ply.yacc as yacc
import enum
import uuid
import os
import logging
import sys
import select
from multiprocessing import Process
from multiprocessing import Value
from multiprocessing import Pipe
import subprocess
import requests
import requests.adapters
from web3 import Web3
from dotenv import load_dotenv
logg = logging.getLogger()
logg.setLevel(logging.DEBUG)
tokens = (
'ID',
'NOID',
'HEX',
'LABEL',
'VALUE',
'END',
"ID",
"NOID",
"HEX",
"LABEL",
"VALUE",
"END",
)
t_ID = r'[a-zA-Z0-9]+(-[a-zA-Z0-9]+)+'
t_NOID = r'\-'
t_LABEL = r'[a-zA-Z_]+'
t_VALUE = r'\d+'
t_END = r'\n'
t_HEX = r'0x([a-fA-F0-9])+'
t_ID = r"[a-zA-Z0-9]+(-[a-zA-Z0-9]+)+"
t_NOID = r"\-"
t_LABEL = r"[a-zA-Z_]+"
t_VALUE = r"\d+"
t_END = r"\n"
t_HEX = r"0x([a-fA-F0-9])+"
#def t_VALUE(t):
# def t_VALUE(t):
# r'\d+'
# t.value = int(t.value)
#def t_HEX(t):
# def t_HEX(t):
# r'0x([a-fA-F0-9])+'
#print(t)
#try:
# t.value = bytes.fromhex(t.value)
#except:
# return False
#return t.value
#t.value = t.value
# print(t)
# try:
# t.value = bytes.fromhex(t.value)
# except:
# return False
# return t.value
# t.value = t.value
# pass
t_ignore = ' \t'
t_ignore = " \t"
def t_error(t):
print("problem: ", t.value[0])
t.lexer.skip(1)
lexer = lex.lex()
load_dotenv()
# Chain Params
chainId = os.getenv("CHAIN_ID", "44787")
rpc = os.getenv("RPC", "https://alfajores-forno.celo-testnet.org/")
gas_cap = os.getenv("GAS_FEE_CAP", "35000000000")
master_private_key = os.getenv("MASTER_PRIVATE_KEY")
token_index = os.getenv("TOKEN_INDEX", "0xD774bc082003eaF8DF74eEcD43AD44F03D488418")
gas_topup = os.getenv("GAS_TOPUP", "0.01ether")
bearer_token = os.getenv("BEARER_TOKEN")
w3 = Web3(Web3.HTTPProvider(rpc))
#
#data = '''
#FOOBAR uf-2etg 0xa3bdefa momo 123
# data = '''
# FOOBAR uf-2etg 0xa3bdefa momo 123
#
#BARBAR
#BAZ
# BARBAR
# BAZ
#
#BASFB foo-bar-baz
# BASFB foo-bar-baz
#'''
#
#lexer.input(data)
# lexer.input(data)
#
#while True:
# while True:
# tok = lexer.token()
# if not tok:
# break
# print(tok)
class VoucherTransfer:
def __init__(
self,
to_address=None,
from_address=None,
amount=None,
token_address=None,
decimals=None,
):
self.to_address = to_address
self.from_address = from_address
self.decimals = decimals
self.amount = amount
self.token_address = token_address
class VoucherDetail:
def __init__(self, name=None, symbol=None, decimals=None, owner=None, address=None):
self.name = name
self.owner = owner
self.address = address
self.symbol = symbol
self.decimals = decimals
class CmdId(enum.IntEnum):
KEY_CREATE = 0x1
VOUCHER_CREATE = 0x10
@@ -80,14 +138,15 @@ class CmdId(enum.IntEnum):
class Agent:
def __str__(self):
return self.__class__.__name__ + ':' #{}'.format(self.__class__.__name__, self.v)
return (
self.__class__.__name__ + ":"
) # {}'.format(self.__class__.__name__, self.v)
class AddressAgent(Agent):
def __init__(self, v):
self.v = bytes.fromhex(v[2:])
def __str__(self):
return Agent.__str__(self) + self.v.hex()
@@ -99,8 +158,8 @@ class NameAgent(Agent):
def __str__(self):
return Agent.__str__(self) + self.v
class Cmd:
class Cmd:
def __init__(self, cmd):
self.c = CmdId[cmd]
self.i = None
@@ -114,9 +173,21 @@ class Cmd:
self.s = None
self.n = None
def __str__(self):
return "[{:02d}]{} i={} v={} a={} f={} t={} k={} d={} p={} s={} n={}".format(self.c, self.c.name, self.i, self.v, self.a, self.f, self.t, self.k, self.d, self.p, self.s, self.n)
return "[{:02d}]{} i={} v={} a={} f={} t={} k={} d={} p={} s={} n={}".format(
self.c,
self.c.name,
self.i,
self.v,
self.a,
self.f,
self.t,
self.k,
self.d,
self.p,
self.s,
self.n,
)
def to_store(v):
@@ -133,19 +204,19 @@ def to_agent(v):
def p_cmd(p):
'''cmd : key_create
| voucher_mint
| voucher_transfer
| voucher_create
| pair
'''
"""cmd : key_create
| voucher_mint
| voucher_transfer
| voucher_create
| pair
"""
p[0] = p[1]
def p_key_create(p):
'''key_create : change_label LABEL LABEL
| change_label LABEL LABEL HEX
'''
"""key_create : change_label LABEL LABEL
| change_label LABEL LABEL HEX
"""
o = p[1]
o.f = NameAgent(p[2])
o.t = to_store(p[3])
@@ -155,21 +226,21 @@ def p_key_create(p):
def p_voucher_mint(p):
'''voucher_mint : change_label hv
| change_label nv
'''
"""voucher_mint : change_label hv
| change_label nv
"""
o = p[1]
if o.c.value & 0x10 == 0:
raise ValueError("not a voucher command")
o.v = int(p[2][1])
o.a = to_agent(p[2][0])
p[0] = o
p[0] = o
def p_voucher_create(p):
'''voucher_create : change_label LABEL LABEL VALUE
| change_label LABEL LABEL VALUE VALUE VALUE
'''
"""voucher_create : change_label LABEL LABEL VALUE
| change_label LABEL LABEL VALUE VALUE VALUE
"""
o = p[1]
if o.c.value & 0x10 == 0:
raise ValueError("not a voucher command")
@@ -179,30 +250,34 @@ def p_voucher_create(p):
if len(p) > 5:
o.d = p[5]
o.p = p[6]
p[0] = o
p[0] = o
def p_voucher_mint_recipient(p):
'''voucher_mint : change_label hv HEX
| change_label nv HEX
| change_label hv LABEL
| change_label nv LABEL
'''
"""voucher_mint : change_label hv HEX
| change_label nv HEX
| change_label hv LABEL
| change_label nv LABEL
"""
o = p[1]
if o.c.value & 0x10 == 0:
raise ValueError("not a voucher command")
o.v = int(p[2][1])
o.a = to_agent(p[2][0])
o.t = to_agent(p[3])
p[0] = o
p[0] = o
def p_voucher_transfer(p):
'''voucher_transfer : change_label hv HEX HEX
| change_label nv HEX HEX
| change_label hv LABEL HEX
| change_label nv LABEL HEX
'''
"""voucher_transfer : change_label hv HEX HEX
| change_label nv HEX HEX
| change_label hv LABEL HEX
| change_label nv LABEL HEX
| change_label hv LABEL LABEL
| change_label nv LABEL LABEL
| change_label hv HEX LABEL
| change_label nv HEX LABEL
"""
o = p[1]
if o.c.value & 0x10 == 0:
raise ValueError("not a voucher command")
@@ -210,107 +285,618 @@ def p_voucher_transfer(p):
o.a = to_agent(p[2][0])
o.t = to_agent(p[3])
o.f = to_agent(p[4])
p[0] = o
p[0] = o
def p_nv(p):
'nv : LABEL VALUE'
p[0] = (p[1], p[2],)
"nv : LABEL VALUE"
p[0] = (
p[1],
p[2],
)
def p_hv(p):
'hv : HEX VALUE'
p[0] = (p[1], p[2],)
"hv : HEX VALUE"
p[0] = (
p[1],
p[2],
)
def p_change_label(p):
'''change_label : pair
| pairnoid
'''
"""change_label : pair
| pairnoid
"""
p[0] = p[1]
def p_pair(p):
'pair : LABEL ID'
"pair : LABEL ID"
o = Cmd(p[1])
o.i = p[2]
p[0] = o
def p_pairnoid(p):
'pairnoid : LABEL NOID'
"pairnoid : LABEL NOID"
o = Cmd(p[1])
o.i = str(uuid.uuid4())
p[0] = o
class Router:
def __init__(self):
self.__routes = {}
self.__r = {}
def register(self, cmd_id, fn):
self.__routes[cmd_id] = fn
def sync(self, uid):
o = self.__r[uid]
if o[1] == None:
return None
r = o[1][0].recv()
o = (o[0], None,)
o = (
o[0],
None,
)
o[0].join()
return r
def __wrap(self, uid, fn, cmd):
r = fn(cmd)
self.__r[uid][1][1].send(r)
def exec(self, cmd):
if cmd.c & 0xa0 > 0:
logg.debug("router exec {}".format(cmd))
if cmd.c & 0xA0 > 0:
return self.sync(cmd.i)
fn = self.__routes[cmd.c]
pi = Pipe(False)
po = Process(target=self.__wrap, args=(cmd.i, fn, cmd,))
self.__r[cmd.i] = (po, pi,)
po = Process(
target=self.__wrap,
args=(
cmd.i,
fn,
cmd,
),
)
self.__r[cmd.i] = (
po,
pi,
)
po.start()
po.join()
def finish(self):
print("syncing")
for k, v in self.__r.items():
print("syncing key " + k)
r = self.sync(k)
logg.debug("synced " + k + ": " + r)
print("synced " + k + ": " + r)
def __del__(self):
for k, v in self.__r.items():
r = self.sync(k)
logging.debug("synced " + k + ": " + r)
self.finish()
def noop_handler(cmd):
return str(cmd)
def foo_handler(cmd):
return os.popen('eth-info -p https://celo.grassecon.net').read()
def printMessage(message):
box_width = len(message) + 4
print("+" + "-" * (box_width - 2) + "+")
print("| " + message + " |")
print("+" + "-" * (box_width - 2) + "+")
def find_custodial_address(key_name):
directory = "custodialstore"
filename = f"{key_name}.json"
file_path = os.path.join(directory, filename)
# Check if the file exists with the keyname
if os.path.isfile(file_path):
with open(file_path, "r") as f:
custodial_account = json.load(f)
return custodial_account["address"]
else:
return None
def remove_ansi_escape_codes(text):
return re.sub(r"\u001b\[.*?m", "", text)
def generate_private_key():
"""Generate a new private key."""
web3 = Web3()
account = web3.eth.account.create()
return account.address, w3.to_hex(account.key)
def store_key_in_keystore(keystore_dir, private_key, key_name, address):
# Create the directory if it doesn't exist
if not os.path.exists(keystore_dir):
os.makedirs(keystore_dir)
keystore = {
"key_name": key_name,
"private_key": private_key,
"address": address,
}
store_path = os.path.join(keystore_dir, f"{key_name}.json")
# Save to JSON file (simulated keystore)
with open(store_path, "w") as f:
json.dump(keystore, f)
return store_path
def load_gas(address, nonce):
command = (
f"cast send {address} "
f"--value {gas_topup} "
f"--nonce {nonce} "
f"--private-key {master_private_key} "
f"--rpc-url {rpc} "
f" --json "
)
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.returncode != 0:
raise subprocess.CalledProcessError(
result.returncode, command, output=result.stdout, stderr=result.stderr
)
message = f"Added {gas_topup} to {address}"
printMessage(message)
def create_custodialaccount():
# create custodial account endpoint
url = "http://localhost:5003/api/v2/account/create"
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json",
}
try:
response = requests.post(url, headers=headers)
# Check if the request was successful (status code 200)
if response.status_code == 200:
account = response.json()
public_key = account["result"]["publicKey"]
return public_key
else:
return None
except requests.exceptions.RequestException as e:
print("Error:", e)
return None
def do_custodial_token_transfer(transfer):
# token transfer custodial endpoint
url = "http://localhost:5003/api/v2/token/transfer"
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json",
}
data = {
"from": transfer.from_address,
"to": transfer.to_address,
"amount": str(transfer.amount),
"tokenAddress": transfer.token_address,
}
json_data = json.dumps(data)
try:
response = requests.post(url=url, headers=headers, data=json_data)
# Check if the request was successful (status code 200)
if response.status_code == 200:
transfer = response.json()
return transfer["result"]["trackingId"]
else:
return None
except requests.exceptions.RequestException as e:
print("Error:", e)
return None
def store_voucher(voucher_detail):
vouchers = []
voucher = {
"voucher_address": voucher_detail.address,
"owner": voucher_detail.owner,
"symbol": voucher_detail.symbol,
"decimals": voucher_detail.decimals,
}
vouchers.append(voucher)
try:
with open("vouchers.json", "r") as f:
existing_vouchers = json.load(f)
except FileNotFoundError:
existing_vouchers = []
for entry in existing_vouchers:
vouchers.append(entry)
with open("vouchers.json", "w") as f:
json.dump(vouchers, f)
def key_create_handler(cmd):
key_name = str(cmd.f).split(":")[1]
store_name = cmd.t
keystore_dir = "user_store"
master_address = w3.eth.account.from_key(master_private_key)
nonce = w3.eth.get_transaction_count(master_address.address, "pending")
if cmd.k is None:
address, private_key = generate_private_key()
else:
if cmd.k.startswith("0x"):
private_key = cmd.k[2:]
else:
private_key = cmd.k
address = w3.eth.account.from_key(private_key).address
if store_name == "custodialstore":
address = create_custodialaccount()
if address is None:
raise ValueError("account address cannot be None")
private_key = None
keystore_dir = "custodialstore"
load_gas(address, nonce)
store_key_in_keystore(keystore_dir, private_key, key_name, address)
return address
def voucher_create_handler(cmd):
symbol = cmd.s
if cmd.n is None or cmd.s is None or cmd.v is None:
raise ValueError("cmd.n, cmd.s, and cmd.v must not be None")
voucher_detail = VoucherDetail()
voucher_detail.name = cmd.n
voucher_detail.decimals = cmd.v
random_ascii = "".join(random.choices(string.ascii_letters, k=4)).upper()
try:
with open("vouchers.json", "r") as f:
existing_vouchers = json.load(f)
except FileNotFoundError:
existing_vouchers = []
voucher_symbols = list(map(lambda symbol: symbol["symbol"], existing_vouchers))
if symbol in voucher_symbols:
symbol = symbol + random_ascii
voucher_detail.symbol = symbol
if master_private_key.startswith("0x"):
private_key = master_private_key[2:]
else:
private_key = master_private_key
voucher_detail.owner = private_key
# Command to create a voucher
publish_token = (
f"ge-publish --private-key {voucher_detail.owner} --json "
f"--rpc {rpc} --gas-fee-cap {gas_cap} --chainid {chainId} "
f'p erc20 --name "{voucher_detail.name}" --symbol "{voucher_detail.symbol}"'
)
result = subprocess.run(publish_token, shell=True, capture_output=True, text=True)
if result.returncode != 0:
raise subprocess.CalledProcessError(
result.returncode, publish_token, output=result.stdout, stderr=result.stderr
)
output_lines = result.stderr.strip().split("\n")
deployment_result = output_lines[1]
try:
data = json.loads(deployment_result)
contract_address = data.get("contract_address", None)
voucher_detail.address = contract_address
except json.JSONDecodeError as e:
print("Error parsing JSON:", e)
store_voucher(voucher_detail)
# sleep for 5 second to allow chain to sync
time.sleep(5)
master_address = w3.eth.account.from_key(master_private_key)
nonce = w3.eth.get_transaction_count(master_address.address, "pending")
# Command to add the token to the token index
add_token_to_index = (
f"cast send --private-key {master_private_key} "
f"--nonce {nonce} "
f"--rpc-url {rpc} "
f"{token_index} "
f'"add(address)" {contract_address} '
f" --json "
)
result2 = subprocess.run(
add_token_to_index, shell=True, capture_output=True, text=True
)
if result2.returncode != 0:
raise subprocess.CalledProcessError(
result2.returncode,
add_token_to_index,
output=result2.stdout,
stderr=result2.stderr,
)
message = f"Voucher {voucher_detail.name} created with address {contract_address} and symbol {symbol} and added to token index: {token_index}"
printMessage(message)
return contract_address
def voucher_transfer_handler(cmd):
voucher_transfer = VoucherTransfer()
# Amount to transfer
value = cmd.v # Amount to transfer
is_custodial_address = False
voucher_transfer.amount = value
# Token symbol to transfer
if str(cmd.a).startswith("NameAgent"):
voucher_name = str(cmd.a).split(":")[1]
with open("vouchers.json", "r") as file:
data = json.load(file)
voucher_symbols = list(map(lambda symbol: symbol["symbol"], data))
voucher_address = list(map(lambda address: address["voucher_address"], data))
voucher_decimal = list(map(lambda decimal: decimal["decimals"], data))
if voucher_name in voucher_symbols:
index = voucher_symbols.index(voucher_name)
voucher_transfer.token_address = voucher_address[index]
voucher_transfer.decimals = voucher_decimal[index]
elif str(cmd.a).startswith("AddressAgent"):
voucher_transfer.token_address = "0x" + str(cmd.a).split(":")[1]
else:
raise ValueError(
f"Invalid command: {cmd.t}. Expected 'NameAgent' or 'AddressAgent'."
)
if str(cmd.t).startswith("NameAgent"):
key_name = str(cmd.t).split(":")[1]
custodial_address = find_custodial_address(key_name)
if custodial_address is not None:
to = custodial_address
voucher_transfer.to_address = to
else:
store_path = os.path.join("user_store", f"{key_name}.json")
with open(store_path, "r") as file:
data = json.load(file)
acct = w3.eth.account.from_key(data["private_key"])
to = acct.address
voucher_transfer.to_address = to
elif str(cmd.t).startswith("AddressAgent"):
to = "0x" + str(cmd.t).split(":")[1]
voucher_transfer.to_address = to
else:
raise ValueError(
f"Invalid command: {cmd.t}. Expected 'NameAgent' or 'AddressAgent'."
)
if str(cmd.f).startswith("NameAgent"):
key_name = str(cmd.f).split(":")[1]
custodial_address = find_custodial_address(key_name)
if custodial_address is not None:
is_custodial_address = True
voucher_transfer.from_address = custodial_address
else:
store_path = os.path.join("user_store", f"{key_name}.json")
with open(store_path, "r") as file:
data = json.load(file)
from_private_key = data["private_key"]
elif str(cmd.f).startswith("AddressAgent"):
from_private_key = "0x" + str(cmd.f).split(":")[1]
else:
raise ValueError(
f"Invalid command: {cmd.t}. Expected 'NameAgent' or 'AddressAgent'."
)
amount_transfered = value / pow(10, voucher_transfer.decimals)
if is_custodial_address:
tracking_id = do_custodial_token_transfer(voucher_transfer)
if tracking_id is not None:
message = f"Transfered {amount_transfered} {voucher_name} to {to} "
printMessage(message)
return tracking_id
else:
command = (
f"cast send --private-key {from_private_key} "
f"--rpc-url {rpc} "
f"{voucher_transfer.token_address} "
f'"transfer(address,uint256)" {to} {value}'
f" --json "
)
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.returncode != 0:
raise subprocess.CalledProcessError(
result.returncode, command, output=result.stdout, stderr=result.stderr
)
if result.stderr:
raise ValueError(f"Command failed with error: {result.stderr}")
data = json.loads(result.stdout)
message = f"Transfered {amount_transfered} {voucher_name} to {to} "
printMessage(message)
return data["transactionHash"]
def voucher_mint_handler(cmd):
value = cmd.v
master_address = w3.eth.account.from_key(master_private_key)
nonce = w3.eth.get_transaction_count(master_address.address, "pending")
if str(cmd.t).startswith("NameAgent"):
key_name = str(cmd.t).split(":")[1]
custodial_address = find_custodial_address(key_name)
if custodial_address is not None:
to = custodial_address
else:
store_path = os.path.join("user_store", f"{key_name}.json")
with open(store_path, "r") as file:
data = json.load(file)
acct = w3.eth.account.from_key(data["private_key"])
to = acct.address
elif str(cmd.t).startswith("AddressAgent"):
to = "0x" + str(cmd.t).split(":")[1]
else:
raise ValueError(
f"Invalid command: {cmd.t}. Expected 'NameAgent' or 'AddressAgent'."
)
if str(cmd.a).startswith("NameAgent"):
voucher_symbol = str(cmd.a).split(":")[1]
with open("vouchers.json", "r") as file:
data = json.load(file)
voucher_symbols = list(map(lambda symbol: symbol["symbol"], data))
voucher_address = list(map(lambda address: address["voucher_address"], data))
voucher_owners = list(map(lambda address: address["owner"], data))
if voucher_symbol in voucher_symbols:
index = voucher_symbols.index(voucher_symbol)
s = voucher_address[index]
privatekey = voucher_owners[index]
else:
raise ValueError(f"Voucher with symbol {voucher_symbol} was not found")
elif str(cmd.a).startswith("AddressAgent"):
s = "0x" + str(cmd.a).split(":")[1]
else:
raise ValueError(
f"Invalid command: {cmd.t}. Expected 'NameAgent' or 'AddressAgent'."
)
command = (
f"cast send --private-key {privatekey} "
f"--rpc-url {rpc} "
f"--nonce {nonce} "
f" {s} "
f'"mintTo(address,uint256)" {to} {value}'
f" --json "
)
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.returncode != 0:
raise subprocess.CalledProcessError(
result.returncode, command, output=result.stdout, stderr=result.stderr
)
if result.stderr:
raise ValueError(f"Command failed with error: {result.stderr}")
data = json.loads(result.stdout)
mint_amount = value / 10**6
message = f"Minted {mint_amount} {voucher_symbol} to :{to}"
printMessage(message)
return data["transactionHash"]
parser = yacc.yacc()
cmds = [
"KEY_CREATE foo-bar Foo BAr",
"KEY_CREATE bar-baz Foo BAr 0xabcdef0",
"VOUCHER_MINT - 0xdeadbeef 13 0xfdaf",
"VOUCHER_MINT baz-baz 0xdeadbeef 13 0xfdaf",
"VOUCHER_MINT bar-bar 0xdeadbeef 42",
"VOUCHER_CREATE foo-foo Foo Bar 42",
"VOUCHER_CREATE inky-pinky-blinky Foo Bar 42 44 233",
"VOUCHER_TRANSFER clyde-sue 0xbeeffeed0123 666 foo 0x0fdc",
]
for v in cmds:
running = True
class FileGet:
def __init__(self, o, fp):
self.__running = True
self.__o = o
self.__f = open(fp, "r")
def run(self):
while self.__running:
v = ifc.get()
if v == None:
break
v = v.strip("\n")
if len(v) == 0:
break
r = parser.parse(v)
self.__o.exec(r)
def get(self):
return self.__f.readline()
class WaitGet:
def __init__(self, o, *r):
self.__running = True
self.__o = o
self.__f = r
# TODO: router copy results in missing keys to sync when closing down
def __process(self, f):
while self.__running:
r = select.select([f], [], [])
v = r[0][0].recv()
if v == None:
break
v = v.strip("\n")
if len(v) == 0:
break
r = parser.parse(v)
self.__o.exec(r)
def run(self):
(
fo,
fi,
) = Pipe()
p = Process(target=self.__process, args=(fo,))
p.start()
while self.__running:
v = input("> ")
if v == "":
fi.send(None)
break
fi.send(v)
p.join()
logg.debug("waitget run end")
if __name__ == "__main__":
ifc = None
o = Router()
o.register(CmdId.KEY_CREATE, noop_handler)
o.register(CmdId.VOUCHER_MINT, noop_handler)
o.register(CmdId.VOUCHER_CREATE, noop_handler)
o.register(CmdId.VOUCHER_TRANSFER, foo_handler)
r = parser.parse(v)
o.exec(r)
o.register(CmdId.KEY_CREATE, key_create_handler)
o.register(CmdId.VOUCHER_CREATE, voucher_create_handler)
o.register(CmdId.VOUCHER_MINT, voucher_mint_handler)
o.register(CmdId.VOUCHER_TRANSFER, voucher_transfer_handler)
if len(sys.argv) > 1:
ifc = FileGet(o, sys.argv[1])
else:
ifc = WaitGet(o, sys.stdin)
ifc.run()
o.finish()

View File

@@ -1,29 +1,61 @@
aiee==0.3.2
aiohappyeyeballs==2.4.3
aiohttp==3.10.11
aiosignal==1.3.1
annotated-types==0.7.0
asn1crypto==1.5.1
async-timeout==5.0.1
attrs==24.2.0
bitarray==3.0.0
certifi==2024.8.30
cffi==1.17.1
chainlib==0.5.4
chainlib-eth==0.6.3
charset-normalizer==3.4.0
ckzg==2.0.1
coincurve==15.0.0
confini==0.6.5
cryptography==3.2.1
cytoolz==1.0.0
eth-account==0.13.4
eth-erc20==0.9.0
eth-hash==0.7.0
eth-keyfile==0.8.1
eth-keys==0.6.0
eth-rlp==2.1.0
eth-typing==5.0.1
eth-utils==2.3.2
eth-utils
eth_abi==5.1.0
frozenlist==1.5.0
funga==0.5.7
funga-eth==0.8.0
hexathon==0.1.7
hexbytes==1.2.1
idna==3.10
json-rpc==1.13.0
multidict==6.1.0
nats-py==2.9.0
parsimonious==0.10.0
ply==3.11
potaahto==0.1.2
propcache==0.2.0
pycparser==2.22
pycryptodome==3.10.1
pydantic==2.10.1
pydantic_core==2.27.1
pysha3==1.0.2
python-dotenv==1.0.1
python-gnupg==0.4.9
rlp==3.0.0
pyunormalize==16.0.0
regex==2024.11.6
requests==2.32.3
safe-pysha3==1.0.4
six==1.16.0
toolz==1.0.0
types-requests==2.32.0.20241016
typing_extensions==4.12.2
urllib3==2.2.3
web3==6.1.0
websocket-client==0.57.0
websockets==13.1
yarl==1.15.2

1
vouchers.json Normal file
View File

@@ -0,0 +1 @@
[{"voucher_address": "0xe1E6362959a1E868443F063aD0aBAFab4A41Bcc2", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMPJYQA", "decimals": 6}, {"voucher_address": "0xC4a7c6873b4B57EfFECE675dD8143a86d6DA5f5B", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MESVLIG", "decimals": 6}, {"voucher_address": "0x167691968E9Cc3f81788eaD15cbB18e3437cFb70", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIAVGEF", "decimals": 6}, {"voucher_address": "0xa6E7258b375a98af44aECFc30e1B14BFc60913F0", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMPNRAR", "decimals": 6}, {"voucher_address": "0xeCb48fcEd893757f7a956E556a215f2E8523b067", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MESROLE", "decimals": 6}, {"voucher_address": "0x57B62c8ea79032fF21C95A0CC2b89433259dc8f6", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIAPRNF", "decimals": 6}, {"voucher_address": "0x850FD17BeE9C849c4Ed61B3bA4D3c54576641595", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMPDHKA", "decimals": 6}, {"voucher_address": "0x03ceb8E85d661626C421094ce7A0AF3a3FEEF8A3", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MESPUFA", "decimals": 6}, {"voucher_address": "0x58e3Fa578D42cCd9Af8E8875a37d9C378456C47D", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIAFWKG", "decimals": 6}, {"voucher_address": "0x0CA60E4b670599466125Ef48FC9d733E2B8927E5", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMPFXA", "decimals": 6}, {"voucher_address": "0x4EAbC5070721c9FE18d463Fb75bf6E2A04FbAeE7", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MESAWX", "decimals": 6}, {"voucher_address": "0x803EC23bd814b954E938c2cF28356ea0241629D4", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIAVJA", "decimals": 6}, {"voucher_address": "0xCe131E4f7fC9f23Ee7768E76a8D14852b3B044aF", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMPLV", "decimals": 6}, {"voucher_address": "0xE276Dd85280B962D04F81CCee0eD295a92EC1Fa1", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MESPH", "decimals": 6}, {"voucher_address": "0x4AFC95baBA518ec7F6172fDD720645f7a80B4540", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIAZV", "decimals": 6}, {"voucher_address": "0xAD8e88D24017aFdf5c32deab6fb6104518b75b05", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMPCY", "decimals": 6}, {"voucher_address": "0x4721fE870d23F97Ac0E74980061e922b7180508E", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MESSH", "decimals": 6}, {"voucher_address": "0x7f5d2c9E9bFFe2f80D03a3D609Ce82C2c7fA78C2", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIAWX", "decimals": 6}, {"voucher_address": "0x49666B0E0FFB6A8316708dE7b0CbB0085aC04a63", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "KMP", "decimals": 6}, {"voucher_address": "0x66bA02957ae7D8C624e0BE8a7223D0fF942F6608", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MES", "decimals": 6}, {"voucher_address": "0xC3744229442b410fc5CD5D438a8Bc0A749D8E4eC", "owner": "1e1d0c1519479f68d9c8d07352a8e7e7cb9e2c676bce422f84502412cf3954ba", "symbol": "MIA", "decimals": 6}]