LogoLogo
  • WELCOME TO ALEPH ZERO
  • EXPLORE
    • About Aleph Zero
    • AlephBFT Consensus
    • The Economy of Aleph Zero
    • Where to Buy AZERO
    • Decentralized Governance on Aleph Zero
    • Ecosystem
    • Aleph Zero Foundation Treasury Management
    • Community
    • Glossary
    • Audit & Research Papers
  • USE
    • Wallets
    • Explorer
    • Ledger
    • Telegram Notifications
    • Aleph Zero Signer
      • General introduction
      • What does Signer do?
      • What are Sub-accounts and Sub-account paths?
      • Why is it critical to store your Secret Phrase in a safe place?
      • How to forget and restore accounts?
      • What are Networks?
      • What are Trusted apps?
    • Dashboard
      • Dashboard basics
      • Overview
    • Stake
      • Staking Basics
      • Staking Menu Overview
      • How to Start Staking with the Aleph Zero Dashboard
      • How to Start Staking With the Developer Wallet
      • How to start staking using Ledger hardware wallet
      • How to Change Nominations
      • How to Stop Staking
      • Staking Rewards
      • Validators
      • Commission and Foundation Nodes
      • Proxy Accounts
    • Validate
      • Validating Overview
      • Hardware requirements
      • Running an Aleph Node on Testnet
        • Downloading and running the node
        • Verifying your setup
        • Customizing your setup
        • Building and running from source [advanced]
          • Building from source
          • Set environment variables
          • Download DB snapshot
          • Running the binary
        • Appendix: Ports, addresses, validators, and archivists
      • Running an Aleph Node on Mainnet
        • Running the node
        • Building and running from source [advanced]
      • Setting your identity
      • Making the node validate
      • Securing your validator
      • Troubleshooting
      • Elections and Rewards Math
      • Testnet Validator Airdrop
      • Foundation Nomination Program
    • Using the EVM-layer
    • Governance
      • Token
      • Multisig Accounts
  • BUILD
    • Aleph Zero smart contracts basics
      • Setting up a Testnet account
      • Installing required tools
      • Creating your first contract
      • Deploying your contract to Aleph Zero Testnet
      • Extending your contract
    • Cross contract calls
      • Using references
      • Using dynamic calls
    • Migrating from Solidity
    • Writing e2e tests with ink-wrapper
    • Aleph Zero Signer integration
    • Front-end app: smart contract interaction
    • Security Course by Kudelski Security
      • ink! Developers Security Guideline
      • Lesson 1 - Getting started with ink!
      • Lesson 2 - Threat Assessment
      • Lesson 3 - Integer Overflow
      • Lesson 4 - Signed-integer
      • Lesson 5 - Role-Based Access Control
      • Lesson 6 - Address Validation
      • Lesson 7 - Smart Contract Control
    • Development on EVM-layer
  • PROTOCOL DETAILS
    • Shielder
      • Overview
      • Design against Bad Actors
      • Preliminaries - ZK-relations
      • Notes and Accounts
      • ZK-ID and Registrars
      • Anonymity Revokers
      • PoW Anonymity Revoking
      • Relayers
      • Deterministic Secret Management
      • SNARK-friendly Symmetric Encryption
      • SNARK-friendly Asymmetric Encryption
      • Cryptography
      • Token shortlist
      • User Wallet
      • Versioning
      • PoC
      • Version 0.1.0
      • Version 0.2.0
    • Common DEX
      • Common Whitepaper - Differences
      • Dutch Auctions
  • FAQ
  • Tutorials
    • Withdrawing coins from exchanges
      • How to withdraw your AZERO coins from KuCoin
      • How to withdraw your AZERO coins from MEXC Global
      • How to withdraw your AZERO coins from HTX
  • Setting up or restoring a wallet
    • How to set up or recover your AZERO account using Aleph Zero Signer
    • How to set up or recover your AZERO account using the official mainnet web wallet
    • How to set up or recover your AZERO account using Nova Wallet
    • How to set up or recover your AZERO account using SubWallet
    • How to set up or recover your AZERO account using Talisman
  • Staking
    • How to stake via a direct nomination using the Aleph Zero Dashboard
    • How to stake via a nomination pool using the Aleph Zero Dashboard
    • How to destroy a nomination pool via the Aleph Zero Dashboard
Powered by GitBook
On this page
  • Building and executing the call
  • Selectors
  • Closing remarks

Was this helpful?

  1. BUILD
  2. Cross contract calls

Using dynamic calls

If you find yourself needing more expressive power than the references have to offer, you can use the dynamically constructed calls.

Even though the dynamically constructed calls are the more versatile and powerful method, we encourage you to stick to references if your use case allows it. The drawbacks here are the complete lack of the compiler's assistance when constructing calls: the errors will present themselves only at runtime.

There is only one step involved in the whole process, albeit a little more cumbersome.

Building and executing the call

First of all, you will need some imports:

bulletin_board/lib.rs
use ink::env::{
    call::{build_call, ExecutionInput, Selector},
    DefaultEnvironment,
};

// contract-specific imports:
use highlighted_posts::{HighlightedPostsError, HIGHLIGHT_POST_SELECTOR};

We will paste the whole code snippet and later explain the less obvious parts:

bulletin_board/lib.rs
let call_result: Result<Result<(), HighlightedPostsError>, ink::LangError> =
    build_call::<DefaultEnvironment>()
        .call(highlight_board)
        .exec_input(
            ExecutionInput::new(
                Selector::new(HIGHLIGHT_POST_SELECTOR)
            ).push_arg(author).push_arg(id),
        )
        .transferred_value(cost)
        .returns::<Result<Result<(), HighlightedPostsError>, ink::LangError>>()
        .invoke();

If you come from the OOP world, this style is similar to the 'fluent interface' pattern.

  • We initialize our builder with the build_call method.

  • With call, we specify what contract account we want (this differs from the references, which were initialized with a code hash. Here we need the contract's account, which you can easily find in the Contracts UI).

  • With exec_input we specify which method to call (by using a selector: more on that later) and using push_arg to supply the arguments.

  • By using transferred_value we can send some tokens to the receiving method. Note that this method needs to be marked with the payable macro in order to be able to act on the transfer in any way.

  • We need to specify the return type of the call using returns. Note that each call will have the original return type of the method wrapped in a Result<T, ink::LangError>, on account of all Ink! messages wrapping their return types this way.

  • To actually fire the call we will use the invoke method.

As with references, make sure to inspect the result of the call, handling all the failure cases.

Selectors

You've probably noticed that we didn't use the called method's name in the call above. Instead, we needed to use a selector, which is a number associated with each message in Ink!. There are two ways of going about the selectors: the explicit one, presented above, and the macro-based implicit method.

Explicit selectors

In order to use explicit selectors, you first need to declare them on your 'callee' contract. As you're probably able to guess by now, this is done using a macro:

highlighted_posts/lib.rs
#[ink(message, payable, selector = 7)]
pub fn add(

It is a good practice to create constants for each selector to help eliminate errors. The selectors are actually four-element byte arrays, so we declare it in the following way:

highlighted_posts/lib.rs
pub const HIGHLIGHT_POST_SELECTOR: [u8; 4] = [0, 0, 0, 7];

Of course, to allow other modules to use it, we need to export our constant:

bulletin_board/lib.rs
pub use highlighted_posts::HIGHLIGHT_POST_SELECTOR;

Just as with our reference export, this needs to be placed at the top level.

Now we're able to import it inside our Bulletin Board contract and use it for the ExecutionInput. as in the call snippet above.

Macro-based selectors

In case you don't feel like specifying the selectors manually, you can use the ink::selector_bytes! macro (notice the exclamation mark at the end of the name).

If we use it in our example from before, the Selector instantiation will change to the following:

bulletin_board/lib.rs
Selector(ink::selector_bytes("add"))

Which way you end up using is entirely up to you!

Closing remarks

As the last remark, please remember to always test your contracts on the Testnet first, taking into account different edge cases (including high load and potentially malicious actors interacting with your contract). We are huge advocates of testing even the simplest of contracts but if you're making cross-contract calls, the need for thorough testing is even more apparent.

PreviousUsing referencesNextMigrating from Solidity

Last updated 2 years ago

Was this helpful?

You are now ready to leverage the full potential of Ink! smart contracts and write expressive, complex code. In case you'd like to dive deeper into the cross-contract calls, we encourage you to take a look at the .

official Ink! documentation