Skip to content

Competition Ink!

Noel Kwan edited this page Sep 22, 2021 · 1 revision

Parity's ink! for smart contracts on Substrate / Polka Dot (Rust eDSL compiled to Wasm)

Pros:

  • Do away with all the ad hoc languages for low-level virtual machines.
  • Reuse the type system of Rust for much better contracts.

Cons:

  • Ultimately, still a relatively low-level language on top of which one must build a lot of abstractions before to express adversarial properties of a DApp.

See below the Closing contract written in ink!, and notice that the number of lines of code is far greater than that of the same contract written in Glow:

use ink_env;
use ink_env::Environment;
use ink_lang as ink;

#[ink::chain_extension]
pub trait RecoverId {

    type ErrorCode = SigRecoveryErr;

    // See: https://paritytech.github.io/ink/ink_lang_macro/attr.chain_extension.html#attributes
    // 1101 here is arbitrary, depends on implementation in substrate node.
    #[ink(extension = 1101, returns_result = false)]
    fn recover_id(v: u8, r: [u8; 32], s: [u8; 32]) -> ink_env::AccountId;
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum SigRecoveryErr {
    InvalidSignature,
}

impl ink_env::chain_extension::FromStatusCode for SigRecoveryErr {
    fn from_status_code(status_code: u32) -> Result<(), Self> {
        match status_code {
            0 => Ok(()),
            1 => Err(Self::InvalidSignature),
            _ => panic!("encountered unknown status code"),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum SignEnv {}

impl Environment for SignEnv {
    const MAX_EVENT_TOPICS: usize = 5;

    type AccountId = <ink_env::DefaultEnvironment as Environment>::AccountId;
    type Balance = <ink_env::DefaultEnvironment as Environment>::Balance;
    type Hash = <ink_env::DefaultEnvironment as Environment>::Hash;
    type BlockNumber = <ink_env::DefaultEnvironment as Environment>::BlockNumber;
    type Timestamp = <ink_env::DefaultEnvironment as Environment>::Timestamp;
    type ChainExtension = RecoverId;
}

#[ink::contract(env = crate::SignEnv)]
pub mod closing {
    #[ink(storage)]
    pub struct Closing {
        buyer: AccountId,
        seller: AccountId,
        digest: [u8; 32],
        price: u128,
    }

    // Third parties can verify this for themselves.
    #[ink(event)]
    pub struct Signed {
        #[ink(topic)]
        signee: AccountId,
        #[ink(topic)]
        digest: [u8; 32],
        #[ink(topic)]
        v: u8,
        #[ink(topic)]
        r: [u8; 32],
        #[ink(topic)]
        s: [u8; 32],
    }

    impl Closing {
        /// Buyer calls this with signed document (digest),
        /// and price that should be paid to seller.
        #[ink(constructor)]
        pub fn new(buyer: AccountId, seller: AccountId, digest: [u8; 32], price: u128) -> Self {
            Self { buyer, seller, digest, price }
        }

        /// Seller calls this after verifying digest for Buyer's signature,
        /// and signing it.
        /// This verifies and publishes the Seller's signature against the digest
        /// before releasing payment.
        #[ink(message)]
        pub fn verify_and_withdraw(&mut self, v: u8, r: [u8; 32], s: [u8; 32]) {
            let caller: AccountId = self.env().caller();
            assert!(caller == self.seller);
            assert!(self.price <= self.env().balance(), "Insufficient funds!");

            // Verify seller signature
            assert_eq!(self.seller, self.env().extension().recover_id(v, r, s).unwrap());

            // Publish signature
            self.env().emit_event(Signed {
                signee: self.seller,
                digest: self.digest,
                v, r, s
            });

            // Seller receives their funds, terminate the contract
            self.env().transfer(self.seller, self.price);
            self.env().terminate_contract(self.buyer);
        }
    }
}
Clone this wiki locally