Smart Extensions — Polymath and Parity Technical Engagement

Satyam Agrawal
Polymath Network
Published in
7 min readFeb 18, 2020

--

Polymath is building a purpose-built blockchain for securities — Polymesh. We learned about the strength and power of combining smart contracts and a modular approach on the Ethereum blockchain (Polymath core) and are introducing smart extensions on Polymesh as an analogous concept. Smart extensions are the backbone of security tokens on Polymesh, giving issuers the ability to program specific rules into their security tokens, whilst executing actions in a standardized way to satisfy an issuer’s need for functionality and regulators’ requirements for compliance.

More technically a smart extension in Polymesh is a smart contract, deployed as a WASM blob to the blockchain, which can be referenced by assets in Polymesh. This allows users of Polymesh to extend the functionality of their assets, for example for compliance or settlement purposes, whilst still leveraging the standardized financial primitives used for assets and identity.

This blog will talk about the technical challenges we faced for the seamless interoperability of smart extensions with runtime logic and the solutions we came up with while working closely working with the Parity team. If you want to learn more about the business aspects of Polymesh’s financial primitives and how smart extensions help issuers add an extra layer of financial logic over their assets, please read through this awesome article or the Polymesh Whitepaper.

Challenges faced

Polymath is leveraging the Substrate Framework to build the Polymesh blockchain which provides great flexibility to use different pallets developed and maintained by the Parity team. One of these is pallet_contracts that will facilitate the smart contract functionality being built-in Polymesh.

When we decided to add smart extension functionality in Polymesh, pallet-contracts was missing certain functionality that Polymesh needed to make runtime and smart contract interoperability seamless — a key requirement for smart extensions. Polymath decided to expedite the development of the pallet_contractsmodule and specifically rich interactions between runtime modules and smart contracts, by collaborating with the Parity team with their deep expertise in Substrate. The fruits of this engagement have been integrated back into the main Substrate codebase, so they are available for the community as well. We believe this type of functionality, that combines the extensive control and standardization of runtime modules, with the flexibility of dynamically deployed smart contracts, will ease the life of many projects who are planning to add pallet-contracts to their runtime.

A very brief headline of the functionalities that’s been added during the technical engagement between Polymath & Parity.

  1. The ability to query runtime module storage items from smart contracts.
  2. The ability to call a smart contract function from a runtime module.
  3. The ability to read smart contract storage from a runtime module.

Technical Deep Dive

  • Query runtime module storage from a smart contract.

pallet-contractsis a runtime module that is used to sandbox the smart contract functionality. At runtime level, every runtime is following the same standard procedure of reading/writing the runtime variables in storage that will allow any runtime or sub-module to read other runtime or sub-module storage by using the standard way of reading the runtime storage variables.

Every piece of data is stored in the key-value fashion in the Substrate framework. The key can be derived as:

Singelton variable -> Twox128(module_prefix) ++ Twox128(storage_prefix)

Mapping -> Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key))

eg -

// This module's storage items.decl_storage! {   trait Store for Module<T: Trait> as TemplateModule {   // Just a dummy storage item.   // Here we are declaring a StorageValue, `Something` as a   Option<u32>   // `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored  Something get(fn something): Option<u32>;
FooStore get(fn foo): Option<Foo>;
}}

In the above code,

module_prefix = TemplateModule,

storage_prefix = Something

hence, Key for accessing the Something variable from the runtime storage is: Twox128(TemplateModule)++ Twox128(Something). where Twox128 is a hashing technique used to calculate 128-bit hash & ++ represent the concatenation of the two hashes.

Leveraging the same technique Parity introduces a wrapper function i.e get_runtime_storage() in env_access of ink! — is an eDSL to write WebAssembly based smart contracts— that will take the storage key whose data need to read.

Function to read the runtime storage from the smart contract

In the above code snippet, lines 8–11 represent the calculation of the key as we did above, at line 15 we are calling get_runtime_storage() function to access the runtime storage by providing the calculated key & lines 16–26 represent the error handling & output decoding using Parity Scale codec.

Note- If smart contract wants to read custom type variables then that type should derive parity scale encoding & decoding properties.

Using this functionality any Polymesh based smart extension can access the runtime storage and act accordingly. For example to know whether a compliance rule is valid or not. The contract needs to access asset holder balance, the total supply of the asset and so on.

Trick to create dynamic getter function for the runtime 😉

We can read the storage of the runtime from outside of blockchain by using state RPC function get_storage() but there is no way to add a filtration layer over that data dynamically. Anyone can use the above functionality to create the filtration layer over data using the stateless smart contract and use newly introduced call RPC function of pallet-contracts to call those smart-contract functions without paying any gas for it.

  • Call a smart contract function from the runtime.

This functionality drives the connection of runtime to smart contracts. It will allow calling any function of the smart contract from the runtime and returns the output of the functions. To facilitate, this functionality Parity team adds a non-dispatchable function i.e bare_call in pallet-contracts module. Its signature and functionality is somewhat similar to the low-levelcall function in Solidity. In Solidity, it is used to call an arbitrary function of the smart contract from another contract whilst here it used to call an arbitrary function of a smart contract from a runtime module.

/// Perform a call to a specified contract.
///
/// This function is similar to `Self::call`, but doesn't perform any address lookups and better
/// suitable for calling directly from Rust.
/// # Arguments
/// * `origin`- Caller of the extension
/// * `dest`- Address/AccountId of the smart extension whom get called
/// * `value`- Amount of native currency that need to transfer to the extension
/// * `gas_limit`- Maximum amount of gas passed to successfully execute the function
/// * `input_data` - Encoded data that contains function selector and function arguments values.
pub fn bare_call(
origin: T::AccountId,
dest: T::AccountId,
value: BalanceOf<T>,
gas_limit: Gas,
input_data: Vec<u8>,
) -> ExecResult {

The cost of execution of the bare_call will be paid by the caller of contract i.e origin.

input_data is an encoded value of function selector and its argument values. the selector is the 4-byte hex of the function name i.e keccak(fn do_something()).

Example — function to call smart contract function from the runtime

In Polymesh this functionality is a key for interoperability between Smart Extensions and runtime modules. Using this any issuer on Polymesh can achieve an Extended Compliance Rule, Token Sale Integration, Escrow Management, Corporate Governance, etc. Extended compliance can be attained by adding different compliance logic within the different Smart Extensions and calling them when any transfer happens.

Self::extensions((ticker, SmartExtensionTypes::TransferManager))
.into_iter()
.filter(|tm| Self::extension_details((ticker, tm)).is_archive == false)
.for_each(|tm| {
let result = Self::verify_transfer(ticker, extension_caller.clone(), from_did, to_did, value, tm);
if result == RestrictionResult::VALID {
is_valid = true;
}
else if result == RestrictionResult::INVALID {
is_in_valid = true;
}
else if result == RestrictionResult::FORCE_VALID {
force_valid = true;
}
});

Similarly, token sale integration can be done by introducing a generic investment function in runtime which will call its attached smart extension with the asset.

  • Read the smart contract storage from runtime.

To facilitate this Parity team introduces a non-dispatchable function called get_storage() in pallet-contracts. It will allow the reading storage variable by passing a storage key and the required address of the smart contract.

In the Polymesh scenario, this functionality will be helpful to know the state of the smart extension on the runtime side to pre-validate certain checks before committing changes into the runtime.

RPC functions

During this engagement Parity team also introduced RPC functionality in the contract pallet namely call & get_storage.

call is performed locally without submitting any transactions. Thus executing this won’t change any state. Nonetheless, the calling state-changing contracts is still possible. This method is useful for calling getter-like methods on contracts.

get_storage is to read the contract storage for the given value.

What we discussed above is also covered within the video recording of the substrate and collaborative learning session. and a complete smart contract code & runtime that covers every bit of functionality can be found here.

About Parity

Parity is a core blockchain infrastructure company. Parity is creating an open-source creative commons that will enable people to create better institutions through technology. Learn more at https://parity.io

About Polymath

Polymath makes it easy to create and manage security tokens. The platform simplifies the complex technical challenges of creating a security token and aims to bring the multi-trillion dollar financial securities market to the blockchain. Learn more at https://polymath.network

Joining Polymath

Are you interested in joining the security token revolution? We are always looking for high-quality talent. Check out our careers page at https://polymath.bamboohr.com/jobs/ to apply!

Follow us

Newsletter: https://polymath.network/newsletter
Reddit: https://www.reddit.com/r/PolymathNetwork/
Twitter: https://twitter.com/polymathnetwork
Telegram: https://t.me/polymathnetwork
Facebook: https://www.facebook.com/polymathnetwork/
Youtube: https://www.youtube.com/c/polymathnetwork
Website: https://polymath.network

--

--