Programming Language

Pollux supports Solidity, a user-friendly smart contract development language that encompasses the following characteristics:

  • An object-oriented, high-level language

  • Statically typed

  • Supports inheritance, libraries, and intricate user-defined

Smart Contract Composition

A smart contract comprises both data and functions.

Data:

For any contract data, careful consideration must be given to its assignment – either to storage or memory. Modifying storage in a smart contract can be expensive, so decisions about the data's location should be made judiciously.

Storage:

Persistent data in Pollux is denoted as storage and is represented by state variables. These values are permanently stored on the blockchain. It's crucial to declare the type, allowing the contract to track the required blockchain storage during compilation.

Solidity
contract SimpleStorage {
    uint storedData; // State variable
    // ...
}

Various variable types are available, including address, boolean, integer, fixed-point numbers, fixed-size byte arrays, dynamically-sized byte arrays, Rational and integer literals, String literals, Hexadecimal literals, and Enums.

Address:To ensure compatibility with Ethereum, Solidity processes the data of the address by implementing the following steps on the hex-formatted address of the Pollux network account:

  1. Remove the prefix '37' from the Pollux Hex format address.

  2. Conduct a Mixed-case checksum on the results obtained in the previous step.

    • Mixed-case checksum: Applying a specific logic, certain letters in the address are capitalized, along with the remaining letters in lowercase, creating a checksum. This empowers the address with self-checking capabilities. On average, each address possesses 15 check bits. The overall probability that a randomly generated mistyped address accidentally passes a check is approximately 0.0247%.

For example, this Pollux network account P8mfGw41kXwuHZUQHDGspovq6tPwt6gMqp, the Hex format address is: 3701FBA20CB405734C6B2E704B9ED67C0B5EA74D9E , the value in solidity is:

Solidity
address newAddress =

Memory:

Data that is retained only throughout the execution of a contract function is termed Pollux variables. As these values are not permanently stored on the blockchain, their utilization comes at a considerably lower cost.

Environment variables

Alongside the variables defined within your contract, there exist specific global variables. These are predominantly employed to furnish details about the Pollux blockchain or the ongoing transaction.

Example:

Environment variablesTypeDescription

block.timestamp

uint256

Timestamp of the current block in seconds

block.number

uint

Current block number

block.coinbase

address

Super representative's Node address producing the current block

msg.sender

address

Message sender (current smart contract caller)

msg.value

uint

The amount of SUN send with message

msg.data

bytes

complete call data

msg.sig

bytes4

first 4 bytes of call data (function identifier)

now

uint

current block timestamp (block.timestamp)

Functions

There are two categories of function calls:

  1. Internal: These do not initiate an PVM call. Internal functions and state variables can only be accessed within the current contract or contracts derived from it.

  2. External: These initiate an PVM call. External functions form part of the contract interface, enabling them to be invoked by other contracts and through transactions. Notably, an external function, let's say 'f,' cannot be called internally (i.e., 'f()' does not function, but 'this.f()' is valid).

Functions can further be categorized as public or private:

  1. Public: Public functions can be invoked internally from within the contract or externally through messages.

  2. Private: Private functions are exclusively visible within the contract where they are defined and are not accessible in derived contracts.

An example of a function for updating a state variable on a contract is provided. The parameter, a value of type string, is passed into the function named 'update_name.' Being declared public implies that anyone can access it. Notably, it is not declared as 'view,' allowing it to modify the contract state.

Solidity
function update_name(string value) public {
    dapp_name = value;
}

View functions

Functions committed to not altering the state of the contract's data, often involving query operations. Here is an illustration of such a function that retrieves account balances:

Solidity
function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerPizzaCount[_owner];
}

What constitutes state modification includes:

  • Modifying state variables through writing operations.

  • Emitting events.

  • Creating additional contracts.

  • Employing self-destruct.

  • Transmitting POX through calls.

  • Invoking any function lacking the 'view' or 'pure' modifier.

  • Utilizing low-level calls.

  • Employing inline assembly containing specific opcodes.

Constructor functions

Constructor functions are executed singularly during the initial deployment of the contract. Comparable to constructors in numerous class-based programming languages, these functions typically set the initial values of state variables.

Solidity
// Initializes the contract's data, setting the `owner`
// to the address of the contract creator.
constructor() public {
    // All smart contracts rely on external transactions to trigger its functions.
    // `msg` is a global variable that includes relevant data on the given transaction,
    // such as the address of the sender and the trx value included in the transaction.
    owner = msg.sender;
}

Built-in functions

Apart from the variables and functions explicitly defined within your contract, there are specific built-in functions. As an illustration, consider address.send(), a function enabling the contract to transmit POX to other accounts.

Writing functions

For your function requirements, ensure the presence of:

  • A parameter variable and its type (if the function accepts parameters).

  • Declaration as public or private.

  • Declaration as pure, view, or payable.

  • Returns type (if the function yields a value).

An entire contract could resemble the following. In this example, the constructor function furnishes an initial value for the dapp_name variable.

Solidity
pragma solidity >=0.4.0 <=0.6.0;

contract ExampleDapp {
    string dapp_name; // state variable

    // Called when the contract is deployed and initializes the value
    constructor() public {
        dapp_name = "My Example dapp";
    }

    // Get Function
    function read_name() public view returns(string) {
        return dapp_name;
    }

    // Set Function
    function update_name(string value) public {
        dapp_name = value;
    }
}

Events and Logs

Events enable straightforward querying of occurrences during the execution of a contract transaction. Logs, on the other hand, serve to "write" data to data structures external to smart contracts. While smart contracts cannot directly access log information, logs can offer insights into transactions and events within blocks. Upon the successful execution of a contract transaction, the smart contract can emit events and record logs on the blockchain.

Smart Contract Library

There's no necessity to create every smart contract in your project from the ground up. Numerous open-source smart contract libraries are accessible, offering reusable building blocks for your project, thus sparing you the need to reinvent the wheel.

What's in A Library

Typically, smart contract libraries offer two types of building blocks: reusable behaviors that can be incorporated into your contracts and implementations adhering to various standards.

Behaviors

In the process of crafting smart contracts, it's common to encounter the repetition of certain patterns, such as assigning an admin address for executing protected operations within a contract. Smart contract libraries often offer reusable implementations of these behaviors either as libraries or through inheritance in Solidity.

As an illustration, here's a simplified rendition of the Ownable contract from the OpenZeppelin Contracts library. This contract designates an address as the owner and includes a modifier to limit access to a method exclusively to that owner.

Solidity
contract Ownable {
    address public owner;

    constructor() internal {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(owner == msg.sender, "Ownable: caller is not the owner");
        _;
    }
}

To integrate a building block like this into your contract, you must initially import it and then inherit from it in your own contracts. This enables you to leverage the modifier supplied by the base Ownable contract to secure your custom functions.

Solidity
import ".../Ownable.sol"; // Path to the imported library

contract MyContract is Ownable {
    // The following function can only be called by the owner
    function secured() onlyOwner public {
        msg.sender.transfer(1 ether);
    }
}

Another widely-used illustration is SafeMath. This library furnishes arithmetic functions equipped with overflow checks, a feature not inherently present in the language. It's considered a best practice to employ SafeMath instead of native arithmetic operations to fortify your contract against overflows, which could lead to severe consequences.

Standards

The Pollux community has established various standards known as PRCs: PRC10, PRC20, PRC721, etc. When integrating a PRC into your contracts, it's advisable to seek out standardized implementations instead of developing your own from scratch.

How to Add A Library

Refer to the documentation of the library you are incorporating for precise instructions on its integration into your project. Numerous Solidity contract libraries are available through npm, allowing for a straightforward npm installation. Pay close attention to the language version when adding a library. For example, it is not compatible to use a library designed for Solidity 0.6 if your contracts are authored in Solidity 0.5.

When to Use

Employing a smart contract library in your project offers various advantages. Foremost among them is the time saved, as these libraries provide ready-to-use building blocks that can be seamlessly integrated into your system, eliminating the need to code them from scratch. Security is a significant benefit as well. Open-source smart contract libraries often undergo rigorous scrutiny from the community, given their widespread usage in numerous projects. This continuous review process helps identify and rectify issues, making reusable contract libraries more reliable than application code. Some libraries even undergo external audits to enhance their security measures.

Nevertheless, the use of smart contract libraries comes with the risk of incorporating unfamiliar code into your project. Without a comprehensive understanding of a contract's functionality, there's a possibility of introducing unexpected issues into your system. Always ensure to thoroughly read the documentation of the imported code and review the code itself before integrating it into your project.

Lastly, when deciding whether to include a library, consider its overall adoption within the community. Libraries with widespread usage benefit from a larger community, increasing the number of eyes scrutinizing them for potential issues. When building with smart contracts, prioritize security as the key focus!

Last updated