Skip to content

Instantly share code, notes, and snippets.

@toysrtommy
Last active June 6, 2021 10:55
Show Gist options
  • Save toysrtommy/75ac3d0ecf314942681c0a0fbdfabfa5 to your computer and use it in GitHub Desktop.
Save toysrtommy/75ac3d0ecf314942681c0a0fbdfabfa5 to your computer and use it in GitHub Desktop.
IC: Creating a new neuron (python)
from hashlib import sha224,sha256
import binascii
import re
import os
import base64
import math
import argparse
import sys
import subprocess
import zlib
CA_NNS = "rrkah-fqaaa-aaaaa-aaaaq-cai"
CMD_CALL= "dfx canister --network=https://ic0.app --no-wallet call"
CMD_CALLQ= "dfx canister --network=https://ic0.app --no-wallet call --query"
CMD_BROADCAST = "dfx canister --network=https://ic0.app --no-wallet send {}"
CMD_BROADCAST_Q = "dfx canister --network=https://ic0.app --no-wallet send {}"
CMD_REFRESH_NEURON="%s %s claim_or_refresh_neuron_from_account \"(record {{controller=principal \\\"{}\\\"; memo={}:nat64}})\"" % (CMD_CALL, CA_NNS)
CMD_TRANSFER= "dfx ledger --network https://ic0.app transfer {} --amount {} --memo {}"
## main method for staking a new neuron
def cmd_stakeneuron(amount):
# Get current principal ID
principal = get_principal()
# Generate a neuron account id (a subaccount of governance canister)
dest,memo = nns_subaccount(principal)
dest = dest[2:]
# Transfer the specified amount ICP to the new neuron
transfer = CMD_TRANSFER.format(dest, amount, memo)
print(transfer)
# Notify/refresh the NNS canister on the transfer
refresh = CMD_REFRESH_NEURON.format(principal, memo)
print(refresh)
try_cmd(transfer, 2)
try_cmd(refresh, 2)
CMD_GET_PRINCIPAL = "dfx identity get-principal"
def get_principal():
p = try_cmd(CMD_GET_PRINCIPAL,0).stdout
p = p.decode("ascii")[:63]
return p
# Generate subaccount based on principal
def nns_subaccount(principal_str):
nounce = os.urandom(8)
nounce_s = str(int.from_bytes(nounce, "big"))
print("nounce bytes: " + nounce_s)
# print(principal_str)
principal = principal_to_blob(principal_str)
padding = b'neuron-stake'
subaccount = sha256(b'\x0c' + padding + principal + nounce).hexdigest()
subaccount = bytearray.fromhex(subaccount)
# print("subaccount: " + bytes_to_string(subaccount))
nns_accountid = principal_to_accountid(principal_to_blob_str(CA_NNS), subaccount)
checksum = hex(zlib.crc32(bytes.fromhex(nns_accountid)) & 0xffffffff)
nns_accountid = checksum+nns_accountid
return nns_accountid, nounce_s
def try_cmd(cmd, retries, input=None):
res = subprocess.run(cmd, shell=True,input=input,capture_output=True)
if (res.returncode != 0):
print("cmd execution Error! ")
print(res)
if (retries >0):
time.sleep(2)
print(" ... retrying ")
return try_cmd(cmd, retries-1)
return res
def principal_to_blob_str(principal):
pid = principal_to_blob(principal)
p = "".join('{:02x}'.format(x) for x in pid)
return p
def principal_to_blob(principal):
principal = principal.replace("-","")
# print("extra: " + str(len(str.encode(principal)) % 8))
# Pad as neccessary for base32 decoding
pad = 8 - len(str.encode(principal)) % 8
principal += "=" *pad
# print(principal)
principal = base64.b32decode(principal, True)
principal = principal[4:len(principal)]
p = "".join('{:02d} '.format(x) for x in principal)
# print("blob: " + p)
return principal
def bytes_to_string(b):
return("".join('{:02d} '.format(x) for x in b))
def principal_to_accountid(principal, subaccount=None):
# print("decoding principal ... " + principal)
p=bytes.fromhex(principal)
pad = subaccount
# print("decimal subaccount array (%s): " % len(subaccount) + bytes_to_string(subaccount) )
if (not subaccount):
pad = b'\x00'*32
s = sha224(b'\x0aaccount-id'+p+pad)
return s.hexdigest()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment