Skip to content

Commit

Permalink
Initial version of ink! contract interfacing
Browse files Browse the repository at this point in the history
  • Loading branch information
Arjan Zijderveld committed Dec 14, 2020
1 parent a9fa279 commit 414c373
Show file tree
Hide file tree
Showing 6 changed files with 419 additions and 13 deletions.
94 changes: 93 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ print(receipt.total_fee_amount) # 2749998966
print(receipt.error_message['name']) # 'LiquidityRestrictions'
```

`ExtrinsicReceipt` objects can also be created with all existing extrinsics on-chain:
`ExtrinsicReceipt` objects can also be created for all existing extrinsics on-chain:

```python

Expand All @@ -249,6 +249,98 @@ print(receipt.is_success) # False
print(receipt.weight) # 359262000
print(receipt.total_fee_amount) # 2483332406
print(receipt.error_message['docs']) # [' Sender is not a sub-account.']

for event in receipt.triggered_events:
print(f'* {event.value}')
```

### ink! contract interfacing (work in progress)

#### Deploy a contract

_Tested on Substrate 2.0.0-5ea23999 with the ERC20 contract from the tutorial_:

```python
substrate = SubstrateInterface(
url="ws://127.0.0.1:9944",
)

keypair = Keypair.create_from_uri('//Alice')

# Upload WASM code
code = ContractCode.create_from_contract_files(
metadata_file=os.path.join(os.path.dirname(__file__), 'erc20.json'),
wasm_file=os.path.join(os.path.dirname(__file__), 'erc20.wasm'),
substrate=substrate
)

receipt = code.upload_wasm(keypair)

if receipt.is_succes:
print('* Contrat WASM Uploaded')

for event in receipt.triggered_events:
print(f'* {event.value}')

# Deploy contract
contract = code.deploy(
keypair=keypair, endowment=10**15, gas_limit=1000000000000,
constructor="new",
args={'initial_supply': 1000 * 10**15}
)

print(f'Deployed @ {contract.contract_address}')

else:
print(f'Failed: {receipt.error_message}')
```

#### Work with an existing instance:

```python
contract = ContractInstance.create_from_address(
contract_address="5FV9cnzFc2tDrWcDkmoup7VZWpH9HrTaw8STnWpAQqT7KvUK",
metadata_file=os.path.join(os.path.dirname(__file__), 'erc20.json'),
substrate=substrate
)
```

#### Read data from a contract:

```python
result = contract.read(keypair, 'total_supply')

print('Total supply:', result.value)

result = contract.read(keypair, 'balance_of', args={'owner': '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'})

print('Balance:', result.value)
```

#### Execute a contract call

```python
# Do a gas estimation of the transfer
gas_predit_result = contract.read(keypair, 'transfer', args={
'to': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
'value': 6 * 1000000000000000,
})

print('Gas estimate on local node: ', gas_predit_result.value['success']['gas_consumed'])

# Do the actual transfer
contract_receipt = contract.exec(keypair, 'transfer', args={
'to': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
'value': 6 * 1000000000000000,
}, gas_limit=gas_predit_result.value['success']['gas_consumed'])

if contract_receipt.is_succes:

print('Transfer successful, triggered events:')
for event in contract_receipt.triggered_events:
print(f'* {event.value}')
else:
print('ERROR: ', contract_receipt.error_message)
```


Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ requests~=2.25.0
xxhash>=2.0.0
pytest>=6.1.2

scalecodec>=0.10.37
scalecodec>=0.10.39
py-sr25519-bindings>=0.1.2
py-ed25519-bindings>=0.1.2
py-bip39-bindings>=0.1.6
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
# project page. What does your project relate to?
#
# Note that this is a string of words separated by whitespace, not a list.
keywords='interface polkascan polkadot substrate blockchain rpc', # Optional
keywords='interface polkascan polkadot substrate blockchain rpc kusama', # Optional

# You can just specify package directories manually here if your project is
# simple. Or you can use find_packages().
Expand Down Expand Up @@ -181,7 +181,7 @@
'idna>=2.8',
'requests>=2.25.0',
'xxhash>=1.3.0',
'scalecodec>=0.10.37',
'scalecodec>=0.10.39',
'py-sr25519-bindings>=0.1.2',
'py-ed25519-bindings>=0.1.2',
'py-bip39-bindings>=0.1.6'
Expand Down
52 changes: 43 additions & 9 deletions substrateinterface/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,31 +555,31 @@ def rpc_request(self, method, params, result_handler=None):

@property
def name(self):
if not self.__name:
if self.__name is None:
self.__name = self.rpc_request("system_name", []).get('result')
return self.__name

@property
def properties(self):
if not self.__properties:
if self.__properties is None:
self.__properties = self.rpc_request("system_properties", []).get('result')
return self.__properties

@property
def chain(self):
if not self.__chain:
if self.__chain is None:
self.__chain = self.rpc_request("system_chain", []).get('result')
return self.__chain

@property
def version(self):
if not self.__version:
if self.__version is None:
self.__version = self.rpc_request("system_version", []).get('result')
return self.__version

@property
def token_decimals(self):
if not self.__token_decimals:
if self.__token_decimals is None:
self.__token_decimals = self.properties.get('tokenDecimals')
return self.__token_decimals

Expand All @@ -591,8 +591,11 @@ def token_decimals(self, value):

@property
def token_symbol(self):
if not self.__token_symbol:
self.__token_symbol = self.properties.get('tokenSymbol')
if self.__token_symbol is None:
if self.properties:
self.__token_symbol = self.properties.get('tokenSymbol')
else:
self.__token_symbol = 'UNIT'
return self.__token_symbol

@token_symbol.setter
Expand All @@ -601,8 +604,11 @@ def token_symbol(self, value):

@property
def ss58_format(self):
if not self.__ss58_format:
self.__ss58_format = self.properties.get('ss58Format')
if self.__ss58_format is None:
if self.properties:
self.__ss58_format = self.properties.get('ss58Format')
else:
self.__ss58_format = 42
return self.__ss58_format

@ss58_format.setter
Expand Down Expand Up @@ -2162,6 +2168,34 @@ def encode_scale(self, type_string, value, block_hash=None):
)
return obj.encode(value)

def ss58_encode(self, public_key: str) -> str:
"""
Helper function to encode a public key to SS58 address
Parameters
----------
public_key
Returns
-------
SS58 address
"""
return ss58_encode(public_key, ss58_format=self.ss58_format)

def ss58_decode(self, ss58_address: str) -> str:
"""
Helper function to decode a SS58 address to a public key
Parameters
----------
ss58_address
Returns
-------
Public key
"""
return ss58_decode(ss58_address, valid_ss58_format=self.ss58_format)

# Serializing helper function

def serialize_storage_item(self, storage_item, module, spec_version_id):
Expand Down
Loading

0 comments on commit 414c373

Please sign in to comment.