Sunday, March 7, 2021

 Cadence vs. Solidity  


This article gives a feature comparison between two smart contract programming languages, Solidity and Cadence. Solidify is the main smart contract language on Ethereum blockchain as well as other layer 1 blockchain such as Binance’s BSC. 

 

Cadence is a new smart contract programming language for use on the Flow Blockchain. Cadence introduces new features to smart contract programming that help developers ensure that their code is safe, secure, clear, and approachable. 


Flow Blockchain is the product of Dapper Labs, the company behind the CryptoKitties blockchain game. Led by founders Roham Gharegozlou, Dieter Shirley and Mikhael Naayem, the team developed Flow as a platform for blockchain-based games and digital collectibles. At the time of this writing (March 6th, 2021), the  DAU (daily active users) for flow application NBA Topshot in the past 24H were 266K, while DTU (daily transacting users) were 122K, surpassed both Uniswap and PancakeSwap  as the top Dapp with highest DAU, according to https://dappradar.com/rankings


For Solidity developers who want to try a safer language, this article can be a starting point to compare different features, especially the security features. For smart contract security auditors, your job will get a lot easier with Cadence. The first table gives comparison of the general programming features, and the second table will give comparison on security features. I also provide some background information on some of the features.



Tabel 1: General Features Comparison between Cadence and Solidity

General Features

Cadence

Solidity

Blockchain

Flow

Etherium, BSC

Compiled vs. Interpreted

Currently Interpreted, plan to be compiled to run on Move VM

Compiled to run on EVM

Multiple inheritance

No

Yes

Function overloading

No

Yes

Syntax

Swift and Rust inspired 

JavaScript

Argument labels

Yes, allow description of the meaning of function arguments

Use comments

Floating point arithmetic

Not supported due to deterministic nature of execution

Supported and additional work needed for security and deterministic requirement

Wrapping of Native Token

Flow is itself a smart contract and can be imported directly without a wrapper

ETH needs to be wrapped into WETH to be used in smart contracts.

ownerOf() vs. tokensOfOwnerByIndex(owner, index)

Support query “What tokens do you own” i.e.

tokensOfOwnerByIndex(owner, index)


Support query “Who owns this token“ i.e.

ownerOf()


Tabel 2: Security Features Comparison between Cadence and Solidity

Security Features

Cadence

Solidity

Type

Strong Typed, does not allow implicit or explicit type conversion

Statically typed, allow both implicit or explicit type conversion 

Access Control

Access control is managed through Capability-Based Security, Or  “what you have” (via Resource types and capabilities). As an example, if an Ethereum ERC-20 fungible token allows minting, it probably has a “minter address”, and only allows the mint() method to be called if (msg.sender == minter_address). In Cadence, you’d create a Minter resource object with a mint() method on it. Only someone with access to the Minter object could call mint(), and no further access controls are necessary. You control (or transfer) ownership of the Minter object instead of recording an authorized address.

Access Control is based on “who you are” (via access control lists, or msg.sender)

Resource-oriented programming

Yes, use Linear types with object capabilities

No, Traditional data structure and account based access control

Pre-Condition 

Built-in for functions and transactions, specified in interfaces and enhanced security

Not built-in, Use modifier is a workaround

Post-Condition 

Built-in for functions and transactions, specified in interfaces and enhanced security

Not built-in, Use event emit and processing is a workaround

Function Default Visibility

Private and Capability based

Public (Parity Multisig wallet hack using initWallet)

Underflow or Overflow protection

Yes

Use Open Zeppelin’s safe math library or

Solidity version 0.8

Reentrancy Protection

Yes,

One time use reference can be created from a capability, and references cannot be stored. They need to be lost at the end of a transaction execution. This restriction is to prevent reentrancy attacks

Use OpenZeppelin ReentrancyGuard

Declare variables without initializing

No and more secure

Yes, less secure

Fallback functions

No. But, you can Use pre-conditions and post-conditions

Yes and can cause undesired security problems

modifier functionality

Capability-Based Security for access control is good enough

Yes

Upgradeability

transparent upgradeability built-in

Proxy based - memory layout issues

Or Data separation: complex data types can cause problems during upgrade.  


https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/


Transaction sent to Wrong Address 

Account must contain a copy of the token’s resource type in its storage ensures that funds cannot be lost by being sent to the wrong address

Loss of funds

Security Audit Efforts

Dramatically reduced

Lots of static tools, symbolic execution tools, property testing tools and formal verification tools, but still need to do a lot of manual review. Labor intensive and expensive. 



Statically vs. dynamically typed

Statically-typed programming languages do type checking (i.e., the process of verifying and enforcing the constraints of types on values) at compile-time, whereas dynamically-typed languages do type checks at runtime.


Examples

Statically-typed: C, C++, Java.


Dynamically-typed: Perl, Ruby, Python, PHP, JavaScript.


Strongly vs. weakly typed

Weakly-typed languages make conversions between unrelated types implicitly; whereas, strongly-typed languages don’t allow implicit conversions between unrelated types.


Python is a strongly-typed language:


Compiled Languages

Compiled languages are converted directly into machine code that the processor can execute. As a result, they tend to be faster and more efficient to execute than interpreted languages. They also give the developer more control over hardware aspects, like memory management and CPU usage.


Compiled languages need a “build” step – they need to be manually compiled first. You need to “rebuild” the program every time you need to make a change. In our hummus example, the entire translation is written before it gets to you. If the original author decides that he wants to use a different kind of olive oil, the entire recipe would need to be translated again and resent to you.


Examples of pure compiled languages are C, C++, Erlang, Haskell, Rust, and Go.


Interpreted Languages

Interpreters run through a program line by line and execute each command. Here, if the author decides he wants to use a different kind of olive oil, he could scratch the old one out and add the new one. Your translator friend can then convey that change to you as it happens.


Interpreted languages were once significantly slower than compiled languages. But, with the development of just-in-time compilation, that gap is shrinking.


Examples of common interpreted languages are PHP, Ruby, Python, and JavaScript.


A Small Caveat

Most programming languages can have both compiled and interpreted implementations – the language itself is not necessarily compiled or interpreted. However, for simplicity’s sake, they’re typically referred to as such.


Python, for example, can be executed as either a compiled program or as an interpreted language in interactive mode. On the other hand, most command line tools, CLIs, and shells can theoretically be classified as interpreted languages.


Advantages and disadvantages


Advantages of compiled languages

Programs that are compiled into native machine code tend to be faster than interpreted code. This is because the process of translating code at run time adds to the overhead, and can cause the program to be slower overall.


Disadvantages of compiled languages

The most notable disadvantages are:


Additional time needed to complete the entire compilation step before testing

Platform dependence of the generated binary code


Advantages of interpreted languages

Interpreted languages tend to be more flexible, and often offer features like dynamic typing and smaller program size. Also, because interpreters execute the source program code themselves, the code itself is platform independent.


Disadvantages of interpreted languages

The most notable disadvantage is typical execution speed compared to compiled languages.



1 comment:

  1. I came from your post on the Flow Forums page. It is my first day learning about Cadence as a programming language and I an honored to have stumbled upon your article. I am having trouble starting on the playground page and there isn't many resources or tutorials videos around. Could you point me in the right direction for some additional content on how to learn this code? Is it possible to learn Cadence without any prior programming knowledge. I know basic's but never fully dived in depth into one specific language. Thanks in advance, keep up the great work.

    ReplyDelete