rocklabs-io / ic-py

Python Agent Library for the DFINITY Internet Computer
MIT License
128 stars 27 forks source link

It appears that underscores as keys in a record break the encode function #21

Closed bodily11 closed 2 years ago

bodily11 commented 2 years ago
# Record Test
types = Types.Record({
        'to':Types.Text,
        'fee': Types.Int,
        'memo':Types.Nat64,
        'fromsubaccount':Types.Text,
        #'created_at_time':Types.Record({'timestamp_nanos':Types.Nat64}),
        'amount':Types.Nat64,
    }
)
vals = {
        'to':wallet_address_to_send_ICP,
        'fee': 10000,
        'memo':0,
        'fromsubaccount':'asdf',#convert_wallet_address_to_bytes_array(purchasing_wallet_address)],
        #'created_at_time':[],
        'amount':price,
}
params = [
    {'type': types, 'value': vals}
]
params = encode(params)

The code above works, but if you include an underscore in "from_subaccount" like so, then it gives you an error. I think the underscore is being parsed incorrectly.

mircial commented 2 years ago

Fixed! Now, underscore is supported now! BTW, You can refer to the example directory to see all types of usage

bodily11 commented 2 years ago

YES! This is amazing. Just did my first ICP transfer with the ledger canister straight from ic-py. Feels pretty awesome. Here's my working code if you want to piggy back off of it for examples. Or more likely if you want to point out anything I'm doing in an inefficient way. :)

from ic.identity import Identity
from ic.client import Client
from ic.agent import Agent
from ic import Principal
from ic.candid import encode, decode, Types
import time
import random

# you can download a .pem file from plug wallet
# please keep your private key safe
with open('path/to/.pem','r') as f:
    private_key_1 = f.read()

# load private key as identity
i1 = Identity.from_pem(private_key_1)

# initialize client and create an agent
client = Client(url = "https://ic0.app")
agent = Agent(i1, client)

# custom function to convert wallet address to bytes array
# there has to be a better way, but couldn't figure it out
# so I just created my own function to do it
def convert_wallet_address_to_bytes_array(wallet_address):
    final_text = []
    for x in range(int(len(wallet_address) / 2)):
        my_hexdata = wallet_address[x*2:x*2+2]
        final_text.append(int(my_hexdata,16))
    return final_text

# the ICP ledger canister on mainnet
# WARNING this will transfer real ICP from your plug wallet
ledger_canister_id = 'ryjl3-tyaaa-aaaaa-aaaba-cai' 

# the types expected from a ledger canister transfer call
types = Types.Record({
        'to':Types.Vec(Types.Nat8),
        'fee': Types.Record({'e8s':Types.Nat64}),
        'memo':Types.Nat64,
        'from_subaccount':Types.Opt(Types.Vec(Types.Nat8)),
        'created_at_time':Types.Opt(Types.Record({'timestamp_nanos':Types.Nat64})),
        'amount':Types.Record({'e8s':Types.Nat64})
    }
)

# the values expected from a ledger canister transfer call
values = {
        'to':convert_wallet_address_to_bytes_array(wallet_address_to_send_ICP),
        'fee': {'e8s':int(0.0001E8)},
        'memo':0,
        'from_subaccount':[],
        'created_at_time':[{'timestamp_nanos':time.time_ns()}],
        'amount':{'e8s':price},
}

# the correct structure for parameters
params = [
    {'type': types, 'value': values}
]

# encoding parameters
params = encode(params)

# final update call to the ledger canister to transfer from 
# your identity (wallet address) to the address specified in the request
result = agent.update_raw(ledger_canister_id, 'transfer', params)
Myse1f commented 2 years ago

PR is welcome. You can submit this code as an example and put it in example directory.