# Python SCALE Codec
[![Build Status](https://img.shields.io/github/workflow/status/polkascan/py-scale-codec/Run%20unit%20tests)](https://github.com/polkascan/py-scale-codec/actions?query=workflow%3A%22Run+unit+tests%22)
[![Latest Version](https://img.shields.io/pypi/v/scalecodec.svg)](https://pypi.org/project/scalecodec/) 
[![Supported Python versions](https://img.shields.io/pypi/pyversions/scalecodec.svg)](https://pypi.org/project/scalecodec/)
[![License](https://img.shields.io/pypi/l/scalecodec.svg)](https://github.com/polkascan/py-scale-codec/blob/master/LICENSE)

Python SCALE Codec Library

## Description
Most of the data that the Substrate RPCs output is encoded with the SCALE Codec. This codec is used by the Substrate nodes' internal runtime. In order to get to meaningful data this data will need to be decoded. The Python SCALE Codec Library will specialize in this task.

## Documentation
https://polkascan.github.io/py-scale-codec/

## Installation
```bash
pip install scalecodec
```

## Examples (MetadataV14 runtimes and higher)

### Encode a Call

```python

runtime_config = RuntimeConfigurationObject()
# This types are all hardcoded types needed to decode metadata types
runtime_config.update_type_registry(load_type_registry_preset(name="metadata_types"))

# Decode retrieved metadata from the RPC
metadata = runtime_config.create_scale_object(
    'MetadataVersioned', data=ScaleBytes(response.get('result'))
)
metadata.decode()

# Add the embedded type registry to the runtime config
runtime_config.add_portable_registry(metadata)

call = runtime_config.create_scale_object(
    "Call", metadata=metadata
)
call.encode({
    "call_module": "Balances",
    "call_function": "transfer",
    "call_args": {"dest": "5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY", "value": 3},
})
```

### Decode the result of a `state_getStorageAt` RPC call

```python
event_data = " "

system_pallet = metadata.get_metadata_pallet("System")
event_storage_function = system_pallet.get_storage_function("Events")

event = runtime_config.create_scale_object(
    event_storage_function.get_value_type_string(), metadata=metadata
)
print(event.decode(ScaleBytes(event_data)))
```

### Retrieve type decomposition information of a `RegistryType`:

```python
pallet = metadata.get_metadata_pallet("System")
storage_function = pallet.get_storage_function("BlockHash")

param_type_string = storage_function.get_params_type_string()
param_type_obj = runtime_config.create_scale_object(param_type_string[0])

type_info = param_type_obj.scale_info_type.retrieve_type_decomposition()

print(type_info) 
# {'primitive': 'u32'}
```



## Examples (prior to MetadataV14)

### Decode a SCALE-encoded Compact\<Balance\> 

```python
RuntimeConfiguration().update_type_registry(load_type_registry_preset("default"))
RuntimeConfiguration().update_type_registry(load_type_registry_preset("kusama"))
obj = RuntimeConfiguration().create_scale_object('Compact<Balance>', data=ScaleBytes("0x130080cd103d71bc22"))
obj.decode()
print(obj.value)
```

### Encode to Compact\<Balance\> 

```python
RuntimeConfiguration().update_type_registry(load_type_registry_preset("default"))
obj = RuntimeConfiguration().create_scale_object('Compact<Balance>')
scale_data = obj.encode(2503000000000000000)
print(scale_data)
```

### Encode to Vec\<Bytes\>

```python
RuntimeConfiguration().update_type_registry(load_type_registry_preset("default"))
value = ['test', 'vec']
obj = RuntimeConfiguration().create_scale_object('Vec<Bytes>')
scale_data = obj.encode(value)
print(scale_data)
```

### Add custom types to type registry

```python
RuntimeConfiguration().update_type_registry(load_type_registry_preset("default"))

custom_types = {
    "types": {
        "MyCustomType": "u32",
        "CustomNextAuthority": {
          "type": "struct",
          "type_mapping": [
             ["AuthorityId", "AuthorityId"],
             ["weight", "AuthorityWeight"]
          ]
        }
    }   
}

RuntimeConfiguration().update_type_registry(custom_types)
```

### Or from a custom JSON file

```python
RuntimeConfiguration().update_type_registry(load_type_registry_preset("default"))
RuntimeConfiguration().update_type_registry(load_type_registry_file("/path/to/type_registry.json"))
```

## Multiple runtime configurations
By default a singleton is used to maintain the configuration, for multiple instances: 

```python
# Kusama runtime config
runtime_config_kusama = RuntimeConfigurationObject()
runtime_config_kusama.update_type_registry(load_type_registry_preset("default"))
runtime_config_kusama.update_type_registry(load_type_registry_preset("kusama"))


# Polkadot runtime config
runtime_config_polkadot = RuntimeConfigurationObject()
runtime_config_polkadot.update_type_registry(load_type_registry_preset("default"))
runtime_config_polkadot.update_type_registry(load_type_registry_preset("polkadot"))

# Decode extrinsic using Kusama runtime configuration
extrinsic = runtime_config_kusama.create_scale_object(
    type_string='Extrinsic', 
    metadata=metadata_decoder
)
extrinsic.decode(ScaleBytes(extrinsic_data))

```

## License
https://github.com/polkascan/py-scale-codec/blob/master/LICENSE
