<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kristofer</title>
    <description>The latest articles on Forem by Kristofer (@kristoferlund).</description>
    <link>https://forem.com/kristoferlund</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1281532%2F39896b2c-6d01-490f-b14a-57fe1558ab9d.jpeg</url>
      <title>Forem: Kristofer</title>
      <link>https://forem.com/kristoferlund</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kristoferlund"/>
    <language>en</language>
    <item>
      <title>Build Multi Chain Applications with IC-Alloy and the Internet Computer</title>
      <dc:creator>Kristofer</dc:creator>
      <pubDate>Tue, 17 Dec 2024 21:37:49 +0000</pubDate>
      <link>https://forem.com/kristoferlund/build-multi-chain-applications-with-ic-alloy-and-the-internet-computer-3k84</link>
      <guid>https://forem.com/kristoferlund/build-multi-chain-applications-with-ic-alloy-and-the-internet-computer-3k84</guid>
      <description>&lt;p&gt;One of the major strengths the Internet Computer (ICP) has over other blockchains is its ability to &lt;strong&gt;hold Ethereum, Bitcoin, and other assets natively&lt;/strong&gt;. Not only can ICP smart contracts hold these assets, but they can also interact with smart contracts on other chains.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ic-alloy.dev" rel="noopener noreferrer"&gt;IC-Alloy&lt;/a&gt; is a fork of the Rust-based Ethereum support library &lt;a href="https://alloy.rs" rel="noopener noreferrer"&gt;Alloy&lt;/a&gt;. The goal of IC-Alloy is to vastly simplify interactions with EVM-based blockchains from the &lt;a href="https://internetcomputer.org/" rel="noopener noreferrer"&gt;Internet Computer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the features of the IC-Alloy library, how you can use it to interact with Ethereum, and what kind of Chain Fusion use cases it enables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IC-Alloy extends Alloy with the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ICP Transport Layer&lt;/strong&gt;: Routes requests through the IC EVM RPC canister or an external RPC proxy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ICP Signer&lt;/strong&gt;: Abstracts away the complexity of signing EVM messages and transactions on ICP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ICP Provider&lt;/strong&gt;: Provides a simple interface for interacting with the IC EVM RPC canister.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IC-Alloy has examples!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ic-alloy/ic-alloy-toolkit" rel="noopener noreferrer"&gt;ic-alloy-toolkit&lt;/a&gt;: A collection of examples on how to perform common EVM operations. &lt;a href="https://u4yi6-xiaaa-aaaap-aib2q-cai.icp0.io" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ic-alloy/ic-alloy-basic-wallet" rel="noopener noreferrer"&gt;ic-alloy-basic-wallet&lt;/a&gt;: A basic Ethereum multi-user wallet. &lt;a href="https://7vics-6yaaa-aaaai-ap7lq-cai.icp0.io" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ic-alloy/ic-alloy-dca" rel="noopener noreferrer"&gt;ic-alloy-dca&lt;/a&gt;: A semi-autonomous agent, swapping tokens on Uniswap for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Before we dive into the details of IC-Alloy, let's first talk about what we mean when we say that ICP can hold assets natively on other chains.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does It Mean to Hold Assets on a Blockchain?
&lt;/h2&gt;

&lt;p&gt;Basics first, here is a refresher on what it means to hold assets on a blockchain. If you are a seasoned blockchain developer you might consider skipping this section.&lt;/p&gt;

&lt;p&gt;When you hold an asset on a blockchain, it means you have a balance connected to an address that you control. The address is derived from a cryptographic hash of a public key, while the balance is simply a number representing the amount of the asset you own.&lt;/p&gt;

&lt;p&gt;The balance is recorded on the blockchain’s ledger, and you can transfer it to other addresses by signing transactions with your private key. Whoever controls the private key linked to an address effectively controls the assets at that address.&lt;/p&gt;

&lt;p&gt;Each blockchain uses a cryptographic scheme that defines how keys and addresses are generated, how messages are signed, and how signatures are verified.&lt;/p&gt;

&lt;p&gt;The key to ICP being able to hold assets natively on other chains is that &lt;strong&gt;ICP supports more than one cryptographic scheme!&lt;/strong&gt; In addition to the scheme used by ICP itself, ICP also supports the following schemes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ECDSA&lt;/strong&gt;: This scheme allows ICP smart contracts to securely hold Bitcoin and interact with Ethereum and other EVM chains such as &lt;strong&gt;Avalanche, Cardano, Cosmos, Dogecoin, Filecoin, Hedera, Polkadot, Stacks, and XRP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BIP340&lt;/strong&gt;: A scheme used in Bitcoin, especially in Taproot-related protocols like &lt;strong&gt;Ordinals, Runes, and BRC-20 tokens&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ed25519&lt;/strong&gt;: A scheme used in &lt;strong&gt;Solana, Stellar, Toncoin, Cardano, Polkadot, and Ripple&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ICP supports a powerful cryptographic technology called &lt;strong&gt;threshold signatures&lt;/strong&gt; that allows multiple parties to collaboratively sign messages without exposing their private keys. This technology enables ICP smart contracts to securely derive addresses on behalf of users and sign transactions on other blockchains. Users in turn authenticate and interact with these smart contracts to manage their assets.&lt;/p&gt;

&lt;p&gt;To learn more about this, check out my recent article: &lt;a href="https://kristoferlund.se/blog/241112-what-the-schnorr" rel="noopener noreferrer"&gt;What the Schnorr?! Threshold Signatures on the Internet Computer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing IC-Alloy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://alloy.rs" rel="noopener noreferrer"&gt;Alloy&lt;/a&gt; is a Rust library providing a comprehensive toolset for encoding, decoding, and constructing various Ethereum-specific data types, including transaction and contract objects. Alloy supports the creation of Ethereum-compatible applications by offering developers a type-safe, performant, and ergonomic API for interfacing with Ethereum’s core primitives and executing tasks like building, signing, and decoding transactions.&lt;/p&gt;

&lt;p&gt;Alloy is a great library for Rust developers working with Ethereum, but it lacks built-in support for ICP. This is where &lt;a href="https://ic-alloy.dev" rel="noopener noreferrer"&gt;IC-Alloy&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;Luckily, Alloy is designed to be modular and easily extensible. This makes it possible to fork Alloy and add support for ICP without having to rewrite the entire library from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. An ICP Transport Layer
&lt;/h3&gt;

&lt;p&gt;Smart contracts on ICP are called "canisters." Canisters are composable and can call each other, making it possible to build complex applications by combining multiple canisters.&lt;/p&gt;

&lt;p&gt;To interact with Ethereum, application canisters make calls to the EVM RPC canister. This canister acts as a gateway between the Internet Computer and Ethereum, allowing canisters to send requests to Ethereum's JSON-RPC API and receive responses.&lt;/p&gt;

&lt;p&gt;The EVM RPC canister in turn uses another core feature of ICP—&lt;a href="https://internetcomputer.org/https-outcalls" rel="noopener noreferrer"&gt;HTTPS Outcalls&lt;/a&gt;—making it possible for smart contracts to communicate with the outside world.&lt;/p&gt;

&lt;p&gt;IC-Alloy adds an ICP Transport Layer to Alloy, abstracting away the complexity of routing requests through the EVM RPC canister or an external RPC proxy. This layer ensures that all requests to Ethereum are routed correctly and that requests and responses are properly typed, serialized, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. An ICP Signer
&lt;/h3&gt;

&lt;p&gt;Alloy signers are responsible for... you guessed it... signing transactions. Alloy offers some built-in signers for using Ledger and Trezor physical wallets, as well as various software signers for signing transactions in memory where the private key is accessible to the program.&lt;/p&gt;

&lt;p&gt;IC-Alloy extends Alloy with an ICP Signer that taps into the &lt;a href="https://internetcomputer.org/how-it-works/chain-key-technology" rel="noopener noreferrer"&gt;threshold signature&lt;/a&gt; capabilities of ICP. A canister never has direct access to the private keys used to sign transactions. Instead, the canister sends a request to the subnet nodes, which collaboratively generate the signature using a threshold signing protocol.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. An ICP Provider
&lt;/h3&gt;

&lt;p&gt;Alloy providers facilitate the interaction with Ethereum by managing JSON-RPC requests and responses. Providers offer utility functions for common tasks like querying the state of a smart contract, sending transactions, and estimating gas costs.&lt;/p&gt;

&lt;p&gt;The ICP Provider in IC-Alloy extends the Alloy provider with ICP-specific functionality. For example, ICP canisters cannot easily work with the popular Rust library Tokio, as it is not fully compatible with the Internet Computer. Instead, ICP canisters have to rely on &lt;a href="https://internetcomputer.org/docs/current/developer-docs/smart-contracts/advanced-features/periodic-tasks/" rel="noopener noreferrer"&gt;IC timers&lt;/a&gt; to do things like waiting for a transaction to be mined or subscribing to log events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me Some Code Already
&lt;/h2&gt;

&lt;p&gt;Let's do a walkthrough of how to use IC-Alloy to get the balance of an ERC-20 token on Ethereum. This should give you a good idea of how IC-Alloy works and how you can use it in your own projects.&lt;/p&gt;

&lt;p&gt;You’ll find more docs, examples, etc., on the &lt;a href="https://ic-alloy.dev" rel="noopener noreferrer"&gt;IC-Alloy website&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add IC-Alloy to Your Project
&lt;/h3&gt;

&lt;p&gt;To use the ICP-enabled fork of Alloy in your project, add this to &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;alloy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;git&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/ic-alloy/ic-alloy.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;tag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v0.3.5-icp.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"icp"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Read and Parse the IERC20 Source Code
&lt;/h3&gt;

&lt;p&gt;One of the greatest features of the Alloy library is the &lt;a href="https://docs.rs/alloy-sol-macro/latest/alloy_sol_macro/macro.sol.html" rel="noopener noreferrer"&gt;&lt;code&gt;sol!()&lt;/code&gt;&lt;/a&gt; macro that lets you read and parse Solidity source code. This means we can head over to &lt;a href="https://sepolia.etherscan.io/address/0x1c7d4b196cb0c7b01d743fbc6116a902379c7238#code" rel="noopener noreferrer"&gt;Etherscan&lt;/a&gt; and just copy the interfaces we are interested in. Alloy does all the heavy lifting, converting the interfaces into Rust code that we can use in our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;sol!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;#[sol(rpc)]&lt;/span&gt;
    &lt;span class="s"&gt;"sol/IERC20.sol"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The &lt;code&gt;get_balance&lt;/code&gt; function
&lt;/h3&gt;

&lt;p&gt;Before we break down the code, here is the full &lt;code&gt;get_balance&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[ic_cdk::update]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_balance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="py"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rpc_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RpcService&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;EthSepolia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EthSepoliaService&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Alchemy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IcpConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpc_service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ProviderBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.on_icp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;usdc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IERC20&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usdc&lt;/span&gt;&lt;span class="nf"&gt;.balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="py"&gt;._0&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1. Parse address
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="py"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we parse the address string into an Alloy &lt;code&gt;Address&lt;/code&gt; type. This ensures that the address is valid and causes the function to return an error if it is not.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Create an RPC service
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rpc_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RpcService&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;EthSepolia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;EthSepoliaService&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Alchemy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create an &lt;code&gt;RpcService&lt;/code&gt; that instructs the EVM RPC canister to use Alchemy as the RPC provider. See the &lt;a href="https://internetcomputer.org/docs/current/developer-docs/multi-chain/ethereum/evm-rpc/overview" rel="noopener noreferrer"&gt;list of RPC providers&lt;/a&gt; the EVM RPC canister supports.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Create a config object
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IcpConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpc_service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The config object determines the behavior of the ICP provider and transport when making the request. The &lt;code&gt;new&lt;/code&gt; function takes the &lt;code&gt;RpcService&lt;/code&gt; we created in the previous step and uses default values for the other fields.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Create a provider
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ProviderBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.on_icp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ProviderBuilder&lt;/code&gt; is a helper that allows you to create a provider with a specific configuration. In this case, we use the &lt;code&gt;on_icp&lt;/code&gt; method to create a provider that uses the ICP transport layer.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Creating an instance of the IERC20 contract
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;usdc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IERC20&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How great is this!?&lt;/strong&gt; We can just create an instance of the IERC20 contract by calling the &lt;code&gt;new&lt;/code&gt; method on the &lt;code&gt;IERC20&lt;/code&gt; struct. The &lt;code&gt;new&lt;/code&gt; method takes the address of the contract and the provider we created in the previous step.&lt;/p&gt;

&lt;p&gt;Once set up, we have access to all contract methods defined in the IERC20 interface.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Get the balance
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usdc&lt;/span&gt;&lt;span class="nf"&gt;.balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we call the &lt;code&gt;balanceOf&lt;/code&gt; method on the contract to get the balance of the address. The method returns a &lt;code&gt;Result&lt;/code&gt; that we can match on to get the balance or an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Chain Fusion Applications
&lt;/h2&gt;

&lt;p&gt;You have seen how the threshold signature technology of ICP together with IC-Alloy makes it super easy to interact with Ethereum from ICP smart contracts.&lt;/p&gt;

&lt;p&gt;With Internet Computer lingo, we call these multi chain applications “&lt;a href="https://internetcomputer.org/chainfusion" rel="noopener noreferrer"&gt;Chain Fusion&lt;/a&gt;” applications. By Chain Fusion, we mean applications that seamlessly fuse together blockchains without the need for intermediaries.&lt;/p&gt;

&lt;p&gt;Examples of Chain Fusion use cases include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Decentralized Exchanges (DEXs)&lt;/strong&gt;: Canisters can securely hold assets from multiple chains and facilitate trustless swaps between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Chain Messaging&lt;/strong&gt;: Canisters can send messages and trigger actions on other chains, enabling complex workflows and interoperability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Asset Wallets&lt;/strong&gt;: Canisters can manage a diverse portfolio of assets across various blockchains, providing users with a unified interface for asset management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Co-processing and off-chain computation&lt;/strong&gt;: Canisters can offload heavy computations to other chains and use the results in their own computations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous agents and smart contracts&lt;/strong&gt;: Canisters can act as autonomous agents, interacting with other chains on behalf of users.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;IC-Alloy comes with a collection of examples on how to perform common EVM operations, build wallets, and even create autonomous agents:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/ic-alloy/ic-alloy-toolkit" rel="noopener noreferrer"&gt;ic-alloy-toolkit&lt;/a&gt;: A collection of examples on how to perform common EVM operations. &lt;a href="https://u4yi6-xiaaa-aaaap-aib2q-cai.icp0.io" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ic-alloy/ic-alloy-basic-wallet" rel="noopener noreferrer"&gt;ic-alloy-basic-wallet&lt;/a&gt;: A basic Ethereum multi-user wallet. &lt;a href="https://7vics-6yaaa-aaaai-ap7lq-cai.icp0.io" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ic-alloy/ic-alloy-dca" rel="noopener noreferrer"&gt;ic-alloy-dca&lt;/a&gt;: A semi-autonomous agent, swapping ERC-20 tokens on Uniswap for you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Let's build!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>rust</category>
      <category>ethereum</category>
      <category>icp</category>
    </item>
    <item>
      <title>What the Schnorr?! Threshold Signatures on the Internet Computer</title>
      <dc:creator>Kristofer</dc:creator>
      <pubDate>Tue, 12 Nov 2024 15:14:21 +0000</pubDate>
      <link>https://forem.com/kristoferlund/what-the-schnorr-threshold-signatures-on-the-internet-computer-386i</link>
      <guid>https://forem.com/kristoferlund/what-the-schnorr-threshold-signatures-on-the-internet-computer-386i</guid>
      <description>&lt;p&gt;The Internet Computer (ICP) recently added support for Threshold Schnorr signatures alongside its existing Threshold ECDSA support. &lt;/p&gt;

&lt;p&gt;What is that anyway?! &lt;strong&gt;Schnorr what?!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article explains these complex cryptographic concepts simply, highlighting the use cases they unlock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Threshold signatures allow ICP smart contracts (canisters) to &lt;strong&gt;securely derive addresses on other blockchains&lt;/strong&gt; and sign transactions on their behalf.&lt;/li&gt;
&lt;li&gt;ICP supports signature schemes compatible with widely used blockchains, including &lt;strong&gt;Bitcoin, Ethereum, Solana and more than twenty other chains&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;With this support, a canister on ICP can &lt;strong&gt;natively hold Bitcoin, Ethereum, and other assets&lt;/strong&gt;, and sign transactions directly on those chains without intermediaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, let’s understand the basics of threshold signatures, a powerful technology that enables secure, multi-party signing without exposing private keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Threshold Signatures: A Primer
&lt;/h2&gt;

&lt;p&gt;In traditional digital signatures, a single private key is used to sign a message, and the corresponding public key can be used to verify the signature. In a blockchain context, the public key is used to derive an address, and the private key is used to sign transactions. If you are using Ledger to interact with a blockchain, the private key is stored on the device. If you use Metamask, the private key is stored in your browser.&lt;/p&gt;

&lt;p&gt;In threshold signatures, the private key is instead divided into multiple shares, and a subset of these shares is required to collectively sign a message. This approach offers several advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Since no single entity possesses the entire private key, the risk of a single point of failure or compromise is reduced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience&lt;/strong&gt;: Even if some key shares are compromised, the threshold number of shares required for signing ensures that the signature remains secure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Threshold signatures can be used for multi-signature schemes, where multiple parties collectively sign a message, or for threshold schemes where a subset of nodes in a network collaboratively sign transactions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On ICP, the nodes of the subnet hosting a canister hold the key shares. These nodes are collectively responsible for generating and managing the key shares required for threshold signatures. &lt;/p&gt;

&lt;h2&gt;
  
  
  Unique Public Keys for Canister Identity and Security
&lt;/h2&gt;

&lt;p&gt;Every canister on the Internet Computer has its own unique public key, acting as its secure identifier. Canisters never have direct access to their private keys, ensuring that sensitive operations remain protected. When a canister needs to sign a transaction or message, it sends a request to the subnet nodes, which collaboratively generate the signature using a threshold signing protocol. &lt;/p&gt;

&lt;p&gt;To interact with other blockchains, a canister can derive addresses on those chains based on its public key. This capability allows a canister to hold assets on other chains and even sign transactions directly on their behalf, &lt;strong&gt;as long as it supports the same signature scheme&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Public key cryptography uses various forms of mathematical curves to generate keys and signatures. On top of these curves, different signature schemes are built, each with its own encoding and security properties. &lt;strong&gt;A cryptographic scheme defines how keys are generated, how messages are signed, and how signatures are verified&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s explore the two signature schemes supported by ICP and the blockchains they enable canisters to interact with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Threshold ECDSA
&lt;/h2&gt;

&lt;p&gt;The first signature scheme supported by ICP was Threshold ECDSA. This scheme allows canisters to securely hold Bitcoin, interact with Ethereum and other EVM chains, and sign transactions on these chains using ECDSA signatures. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzdcsnwe0kt6avl94e89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzdcsnwe0kt6avl94e89.png" alt="secp256k1" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ECDSA relies on the elliptic curve &lt;strong&gt;secp256k1&lt;/strong&gt;, a curve chosen for its efficiency and security in cryptographic applications. Developed by the Standards for Efficient Cryptography Group (SECG), secp256k1 was selected by Bitcoin’s creator, Satoshi Nakamoto, for its strong security properties and computational efficiency, making it ideal for digital signatures. Its designation as a Koblitz curve means it has certain mathematical properties that optimize performance, especially for fast computation, which is crucial in high-transaction environments like Bitcoin. The curve’s 256-bit length offers robust protection, balancing security with practical speed for modern cryptographic needs.&lt;/p&gt;

&lt;p&gt;Many other chains also build on ECDSA, making it a widely used signature scheme in the blockchain space. Some other chains that use ECDSA include: &lt;strong&gt;Avalanche, Cardano, Cosmos, Dogecoin, Filecoin, Hedera, Polkadot, Stacks and XRP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://internetcomputer.org/docs/current/developer-docs/smart-contracts/signatures/t-ecdsa" rel="noopener noreferrer"&gt;Learn more about Threshold ECDSA&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Threshold Schnorr
&lt;/h2&gt;

&lt;p&gt;With the recent introduction of threshold Schnorr signature scheme, ICP expands its cryptographic capabilities by enabling canisters to sign messages on two different curves: &lt;strong&gt;secp256k1&lt;/strong&gt; (following BIP340 standards) and &lt;strong&gt;Curve25519&lt;/strong&gt;. This allows for even greater flexibility and compatibility across blockchain ecosystems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsqi1zjb20gkvu4894qi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsqi1zjb20gkvu4894qi.png" alt="curve25519" width="629" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Curve25519 is a slightly newer elliptic curve that offers similar security properties to secp256k1 but with different performance characteristics. It’s optimized for both speed and security, making it efficient and resistant to certain implementation vulnerabilities. Curve25519’s structure also makes it faster for verification, making it ideal for high-performance applications.&lt;/p&gt;

&lt;p&gt;Threshold Schnorr on ICP supports two main algorithms, each with its own signature encoding:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;BIP340&lt;/strong&gt; on secp256k1: This curve and encoding are widely used in Bitcoin, especially in Taproot-related protocols like &lt;strong&gt;Ordinals, Runes, and BRC-20 tokens&lt;/strong&gt;. This compatibility allows ICP canisters to directly interact with Bitcoin’s Taproot features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ed25519&lt;/strong&gt;: Ed25519 is a signature scheme that builds on Curve25519, using it in the Edwards form. This option provides compatibility with protocols and ecosystems that rely on Ed25519-based signatures. Ed25519 is a specific implementation of EdDSA (Edwards-curve Digital Signature Algorithm), a more general signature scheme known for its strong security and high performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Offering EdDSA opens up support for a wide range of additional chains, including &lt;strong&gt;Solana, Stellar, Toncoin, Cardano, Polkadot, and Ripple&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://internetcomputer.org/docs/current/developer-docs/smart-contracts/signatures/t-schnorr" rel="noopener noreferrer"&gt;Learn more about Threshold Schnorr&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting Threshold Signatures to Work
&lt;/h2&gt;

&lt;p&gt;Let's wrap up this short article. &lt;/p&gt;

&lt;p&gt;You have learnt how threshold signatures allow ICP canisters to interact natively with other blockchains, securely holding assets and signing transactions. This capability opens up a world of possibilities for decentralized applications and cross-chain interactions.&lt;/p&gt;

&lt;p&gt;Using Internet Computer lingo, we call this capability “&lt;a href="https://internetcomputer.org/chainfusion" rel="noopener noreferrer"&gt;chain fusion&lt;/a&gt;”, where different blockchains can seamlessly interact and share assets without the need for intermediaries. &lt;/p&gt;

&lt;p&gt;Examples of chain fusion use cases include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Decentralized Exchanges (DEXs)&lt;/strong&gt;: Canisters can securely hold assets from multiple chains and facilitate trustless swaps between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Chain Messaging&lt;/strong&gt;: Canisters can send messages and trigger actions on other chains, enabling complex workflows and interoperability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Asset Wallets&lt;/strong&gt;: Canisters can manage a diverse portfolio of assets across various blockchains, providing users with a unified interface for asset management.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Chain fusion and threshold signatures are exciting developments promising a future where blockchains can seamlessly interact and share assets in a trustless, secure manner. With support for both Threshold ECDSA and Threshold Schnorr signatures, the Internet Computer now supports most major blockchains.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://internetcomputer.org/docs/current/developer-docs/getting-started/network-overview" rel="noopener noreferrer"&gt;internetcomputer.org&lt;/a&gt; website provides detailed documentation on how to implement threshold signatures in your smart contracts. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's build!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>beginners</category>
      <category>web3</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Introducing: Composite Attestations Engine (CATTS)</title>
      <dc:creator>Kristofer</dc:creator>
      <pubDate>Wed, 20 Mar 2024 09:47:11 +0000</pubDate>
      <link>https://forem.com/kristoferlund/introducing-composite-attestations-engine-catts-342f</link>
      <guid>https://forem.com/kristoferlund/introducing-composite-attestations-engine-catts-342f</guid>
      <description>&lt;p&gt;&lt;strong&gt;This article introduces the concept of composite attestations and the Composite Attestations Engine (CATTS). It gives a high level overview of the concept and a draft of the planned features of the engine.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Composite attestations&lt;/strong&gt; are a new type of Ethereum &lt;a href="https://attest.sh"&gt;attestation&lt;/a&gt; combining data from multiple sources to form a unified and verifiable credential.&lt;/li&gt;
&lt;li&gt;Use cases include:

&lt;ul&gt;
&lt;li&gt;Transforming attestations from one type to another&lt;/li&gt;
&lt;li&gt;Bridging attestations between EVM chains&lt;/li&gt;
&lt;li&gt;Make ETH attestations available to non EVM chains (ICP, Solana)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;CATTS have not been implemented yet, the project will be built during Q2, 2024.&lt;/li&gt;
&lt;li&gt;Follow CATTS! &lt;a href="https://t.me/+TTwQJIiT6040YmM0"&gt;Telegram - CATTS Community&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Planned features&lt;/li&gt;
&lt;li&gt;Future features&lt;/li&gt;
&lt;li&gt;Flow&lt;/li&gt;
&lt;li&gt;Recipe&lt;/li&gt;
&lt;li&gt;Composite Attestation&lt;/li&gt;
&lt;li&gt;Receipt&lt;/li&gt;
&lt;li&gt;Example run: User has attestation 1 AND attestation 2&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://attest.sh"&gt;Ethereum Attestation Service&lt;/a&gt; (EAS) is an infrastructure public good for making attestations onchain or offchain about anything. Attestations can represent identity, reputation, knowledge, and much more. EAS is a tokenless and free service that is available on mainnet, several L2s, and various testnets. EAS is a great service! It is tokenless and free for anyone to use. &lt;strong&gt;This means it is being used. A lot!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;There is a universe of attestation data out there. EAS provides an API that allows you to query that data which makes integration into websites and apps easy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrs4gq7thvfp8fguyapz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrs4gq7thvfp8fguyapz.jpg" alt="Lots of attestations out there" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say I, as an app, want to offer membership to users that meet certain criteria. I my backend, I can use the EAS API to query all attestations that are relevant to my use case. Then, I write some custom logic to process the data and let the outcome of that logic determine if a user is eligible for membership. Easy!&lt;/p&gt;

&lt;p&gt;But, what if I need to show a proof of the outcome of my logic? What if I need to create an attestation that says "This user is eligible for membership"? I can of course easily create that attestation. But, without knowledge of the data I processed or about the processing logic I ran on the data, how can anyone verify that the attestation I created is correct?&lt;/p&gt;

&lt;p&gt;Wouldn't it be great if there was a way to create attestations based on the result of custom queries and processing logic and have the result of that logic be independently verifiable? That's where &lt;strong&gt;CATTS&lt;/strong&gt;, the &lt;strong&gt;Composite Attestations Engine&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe26j176fhh1cs35u0f65.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe26j176fhh1cs35u0f65.jpg" alt="Join the knowledge of many attestations into one" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CATTS allows for the creation of &lt;strong&gt;composite attestations&lt;/strong&gt; based on custom queries and processing logic. Running on the Internet Computer (ICP) as a smart contract canister, it leverages data from existing attestations via the EAS GraphQL API, ensuring that the creation and verification of attestations are both reliable and transparent. The processing logic is defined as a piece of arbitrary JavaScript code, which is executed securely within the canister environment. The engine also provides a receipt for each run, detailing the settings used, which aids in verifying the correctness of the composite attestations. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltf78v78ty73k5cc98ih.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltf78v78ty73k5cc98ih.jpg" alt="Decentralised secure and realiable" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Planned features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom queries&lt;/strong&gt;: Fetch data from the EAS GraphQL API using custom queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom processing logic&lt;/strong&gt;: Define custom processing logic to create composite attestations based on the result of the queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure execution&lt;/strong&gt;: The processing logic is executed securely within the canister environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Receipts&lt;/strong&gt;: A receipt is created for each run, detailing the settings used, which aids in verifying the correctness of the composite attestations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chain agnostic&lt;/strong&gt;: Run queries on one chain or on multiple chains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifiable&lt;/strong&gt;: The result of the processing logic is independently verifiable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt;: The engine is open source and free to use. Anyone can create and run recipes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost effective&lt;/strong&gt;: Attestation runs can be simulated before they are run. This ensures that the cost of running the canister is minimized.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Advanced settings&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;Allow query chain settings to be overridden on a per run and per query basis.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allow users to "claim" their composite attestations&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Transfers cost of creating attestations to the user.&lt;/li&gt;
&lt;li&gt;Allow the user to claim an attestation using multiple addresses.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Even more chain agnostic&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Allow the creation of attestations on multiple chains.&lt;/li&gt;
&lt;li&gt;Allow querying other attestation services, not just EAS.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZK attestations&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Allow the creation of zero knowledge attestations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmqi4eswf3v3diqt5hbz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmqi4eswf3v3diqt5hbz.jpg" alt="The CATTS engine flow" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flow of creating composite attestations using CATTS is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create recipe&lt;/strong&gt;: Define a recipe that includes custom queries, processing logic and output schema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simulate run&lt;/strong&gt;: Simulate the run to verify the correctness of the recipe. Queries are run in the browser at no cost. A run can be simulated many times during the recipe creation process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run&lt;/strong&gt;: Running the recipe means that the CATTS engine executes all queries and process the result set according to the processing instructions. The run output is saved and a run receipt is created as an attestation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create attestations&lt;/strong&gt;: The CATTS engine creates attestations based on the run output and the output schema.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Recipe
&lt;/h2&gt;

&lt;p&gt;The CATTS recipe is a set of instructions that CATTS uses to create attestations. The recipe is in itself an attestation, consisting of the following parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queries&lt;/li&gt;
&lt;li&gt;Query variables&lt;/li&gt;
&lt;li&gt;Query settings&lt;/li&gt;
&lt;li&gt;Processor&lt;/li&gt;
&lt;li&gt;Output schema&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Queries
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A query fetches data from the EAS GraphQL API. &lt;/li&gt;
&lt;li&gt;Queries are executed in the canister as HTTPS outcalls.&lt;/li&gt;
&lt;li&gt;The result of a query is determined by the query itself and the query variables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AttestationWhereInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;attestations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$where&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above query will return all the recipients of attestations that match the criteriea defined in the &lt;code&gt;where&lt;/code&gt; variable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query variables
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;All variables that are allowed by the EAS GraphQL API schema are allowed in the recipe.&lt;/li&gt;
&lt;li&gt;Every query can have its own set of variables.&lt;/li&gt;
&lt;li&gt;Variables cannot be overridden on a per run basis. This might be a feature in future iterations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"where"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"schemaId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"equals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xCBA...321"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above query and variable will return all the receipents of all attestations that have been created using the schema with UID &lt;code&gt;0xCBA...321&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query settings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every query can have its own settings.&lt;/li&gt;
&lt;li&gt;In the first iteration, the settings available are limited. In future iterations, more advanced settings will be available.&lt;/li&gt;
&lt;li&gt;Settings:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chain: number&lt;/code&gt; - The chain to run the query on.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Processor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;After running the queries, we want to process the result set to create aggregate attestations using arbitrary logic. &lt;/li&gt;
&lt;li&gt;The logic expresses what we want to create attestations for.&lt;/li&gt;
&lt;li&gt;Processors are run in the canister. This is a key feature of CATTS. Running the processor in the canister ensures that the processor is run in a secure environment and that we can trust the result of the processor.&lt;/li&gt;
&lt;li&gt; Processors are written in JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example, imagine a Javascript function that performs the following logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Process the data set and return only those recipients that have attestations for 
"is a human" and "has a gitcoin passport score of 30 or more".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output schema
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The output schema is a Attestation schema that is used to create attestations based on the result of the processor.&lt;/li&gt;
&lt;li&gt;Schemas are defined outside of EEA and are referenced by UID.&lt;/li&gt;
&lt;li&gt;Schema:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;UID: string&lt;/code&gt; - UID referencing an EAS schema.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain: number&lt;/code&gt; - The chain to create the attestations on.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Composite Attestation
&lt;/h2&gt;

&lt;p&gt;A composite attestation is an attestation that is created based on the result of the processor. The attestations are created by the CATTS canister. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every attestation references the "run receipt" attestation in the "referenced attestation" field.&lt;/li&gt;
&lt;li&gt;The CATTS canister has to pay for the attestations it creates. This cost is passed on to the user that is making the run. The cost is determined by the number of attestations that are created and the chain that the attestations are created on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Receipt
&lt;/h2&gt;

&lt;p&gt;A run receipt is created for every run, as a way to verify the correctness of the composite attestations. The receipt is created as an attestation on the same chain as the attestations that were created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All receipts use the same predefined schema.&lt;/li&gt;
&lt;li&gt;Schema:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;recipe_uid: string&lt;/code&gt; - The UID of the recipe that was run.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data_raw: any[]&lt;/code&gt; - The raw data that was returned from the queries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data_processed: any[]&lt;/code&gt; - The data that was returned from the processor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timestamp: number&lt;/code&gt; - The timestamp of the run.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;initiator: string (ethereum address)&lt;/code&gt; - The address that initiated the run.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example run: User has attestation 1 AND attestation 2
&lt;/h2&gt;

&lt;p&gt;The below example shows how to create a composite attestation for a user that has both attestation 1 and attestation 2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recipe
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Query
&lt;/h4&gt;

&lt;p&gt;Fetch all recipients of attestations, determined by the &lt;code&gt;where1&lt;/code&gt; and &lt;code&gt;where2&lt;/code&gt; variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$where1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AttestationWhereInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;attestations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$where1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$where2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AttestationWhereInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;attestations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$where2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Query variables
&lt;/h4&gt;

&lt;p&gt;The above query and variable will return all the receipents of all attestations that have been created using the schema with UID &lt;code&gt;0xCBA...321&lt;/code&gt; and &lt;code&gt;0xABC...123&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"where1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"schemaId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"equals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xCBA...321"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"where2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schemaId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"equals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xABC...123"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Query settings
&lt;/h4&gt;

&lt;p&gt;Note the &lt;code&gt;chain&lt;/code&gt; setting. In the first query, we are running the query on chain 1, and in the second query, we are running the query on chain 10.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Query1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Query2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Processor
&lt;/h4&gt;

&lt;p&gt;Create a merged list with addresses that exist in query 1 and 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recipientsQuery1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recipientsQuery2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;recipientsQuery1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;recipientsQuery2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Output schema
&lt;/h4&gt;

&lt;p&gt;Define the composite attestation schema as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"UID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x123...456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hasAttestation1and2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"boolean"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A user that has both attestation 1 and 2 will receive an attestation with the schema &lt;code&gt;0x123...456&lt;/code&gt; and the data &lt;code&gt;{"hasAttestation1and2": true}&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Run queries
&lt;/h4&gt;

&lt;p&gt;Running the two queries return the following result set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Query1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Query2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xbd0531975D4D273e557E40856320304B39806AD8"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Run processor
&lt;/h4&gt;

&lt;p&gt;After processing the data, only two addresses remain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Create attestations
&lt;/h4&gt;

&lt;p&gt;Create attestations for all addresses in the processor result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attestations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x123...456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hasAttestation1and2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x123...456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hasAttestation1and2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Create run receipt
&lt;/h4&gt;

&lt;p&gt;The run receipt reflects all details of the run and is created as an attestation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"recipe_uid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xabC...867"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data_raw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Query1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Query2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xbd0531975D4D273e557E40856320304B39806AD8"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data_processed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"recipient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x7ED57EdC930333F9130B247797C718234272755F"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1634025600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"initiator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xAAA...111"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;You made it to the end, great work! What's next? Share your feedback with us and join the community!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://t.me/+TTwQJIiT6040YmM0"&gt;Telegram - CATTS Community&lt;/a&gt;
&lt;/h2&gt;

</description>
      <category>ethereum</category>
      <category>attestations</category>
      <category>rust</category>
      <category>smartcontract</category>
    </item>
    <item>
      <title>Create a cross chain ETH/ICP application using Azle and TypeScript</title>
      <dc:creator>Kristofer</dc:creator>
      <pubDate>Fri, 16 Feb 2024 08:58:41 +0000</pubDate>
      <link>https://forem.com/kristoferlund/create-a-cross-chain-ethicp-application-using-azle-and-typescript-dg3</link>
      <guid>https://forem.com/kristoferlund/create-a-cross-chain-ethicp-application-using-azle-and-typescript-dg3</guid>
      <description>&lt;h2&gt;
  
  
  A TypeScript smart contract with a React/Vite frontend using Sign in with Ethereum (SIWE) for authentication.
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://internetcomputer.org/"&gt;Internet Computer&lt;/a&gt; (ICP) is a blockchain network designed to host and execute smart contracts, offering a secure and scalable platform for decentralized applications and data storage.&lt;/p&gt;

&lt;p&gt;Smart contracts on ICP are called "canisters" and can be written in a variety of programming languages, including Motoko, Rust, C, and now... TypeScript, thanks to &lt;a href="https://github.com/demergent-labs/azle"&gt;Azle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article looks at how you can get started building canisters in TypeScript and how you can use &lt;a href="https://eips.ethereum.org/EIPS/eip-4361"&gt;Sign in with Ethereum&lt;/a&gt; (SIWE) to easily authenticate users. &lt;strong&gt;Building cross-chain applications has never been easier!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we dig in, let's look more closely at how ICP works and how it differs from other blockchain networks.&lt;/p&gt;

&lt;h2&gt;
  
  
  ICP runs full-stack applications on the blockchain
&lt;/h2&gt;

&lt;p&gt;ICP introduces a novel approach to blockchain technology, offering a decentralized and serverless cloud infrastructure. Unlike traditional blockchains, ICP employs "canisters", an advanced form of smart contracts, to enable the creation of scalable and tamperproof applications directly on the blockchain. This structure allows for the development of a wide range of applications, from social networks to enterprise systems, without relying on external servers or cloud services. Furthermore, ICP's unique reverse gas model simplifies user interaction with blockchain applications, as it doesn't require users to hold tokens or set up a wallet, making it more accessible and user-friendly compared to other blockchain platforms.&lt;/p&gt;

&lt;p&gt;Canisters are compiled to WebAssembly. Once deployed, they can be accessed by users through a web interface or through other canisters. Canisters run in full isolation from each other and can be composed to form larger applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Azle to write TypeScript canisters
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/demergent-labs/azle"&gt;Azle&lt;/a&gt;, developed by &lt;a href="https://github.com/demergent-labs"&gt;Demergent Labs&lt;/a&gt;, is a significant advancement for the ICP ecosystem, enabling TypeScript developers to write canisters. It achieves feature parity with existing Rust and Motoko CDKs, meaning developers can access almost all IC functionality through TypeScript. This integration not only simplifies the development process for those familiar with TypeScript but also enriches the ICP developer community by incorporating the extensive resources and tools available in the TypeScript ecosystem. Demergent Labs also provides &lt;a href="https://github.com/demergent-labs/kybra"&gt;Kybra&lt;/a&gt;, a Python based CDK.&lt;/p&gt;

&lt;p&gt;One goal of Azle is that you should eventually be able to run virtually any Node.js backend code on ICP. Already today, you can run Express, Apollo Server, SQLite, and many other popular Node.js libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign in with Ethereum (SIWE) for cross-chain authentication
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://eips.ethereum.org/EIPS/eip-4361"&gt;SIWE&lt;/a&gt; standard defines a protocol for off-chain authentication of Ethereum accounts. At the core of the protocol is the SIWE message, which is a signed message that contains the Ethereum address of the user and some additional metadata. The SIWE message is signed by the user's Ethereum wallet and then sent to the application's backend. The backend verifies the signature and Ethereum address and then creates a session for the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kristoferlund/ic-siwe-react-demo-ts"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfydkb24g34vhe1fgsho.png" alt="Siwe for ICP" width="800" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's build!
&lt;/h2&gt;

&lt;p&gt;This article is not a follow-along step-by-step tutorial, but rather a guide to get you started building your own cross-chain applications. Instead of providing a full tutorial that would run the risk of becoming too lengthy, I will dive in and explain critical parts of the example repository this article is based on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kristoferlund/ic-siwe-react-demo-ts"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39pshksq59y8xmupon31.png" alt="SIWE React demo app" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example application allows users to connect their Ethereum wallet and then login using SIWE. After logging in, users can create a user profile with their name and image. This profile is stored in a backend canister. In the frontend of the application, all user profiles are displayed in a list.&lt;/p&gt;

&lt;p&gt;The app is composed of three canisters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ic_siwe_provider&lt;/code&gt; - A pre-built canister that provides the SIWE authentication functionality.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;backend&lt;/code&gt; - The Azle TypeScript canister that stores user profiles and provides an API for the frontend application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;frontend&lt;/code&gt; - A React/Vite application that interact with the backend and SIWE provider canisters. Yes, ICP can &lt;a href="https://kristoferlund.se/blog/240207-publish-static-website"&gt;host frontend applications&lt;/a&gt; as well!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find the full code for the example application on GitHub: &lt;a href="https://github.com/kristoferlund/ic-siwe-react-demo-ts"&gt;ic-siwe-react-demo-ts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the IC SDK
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/dfinity/sdk"&gt;IC SDK&lt;/a&gt; is the software development kit used for creating and managing canisters. The IC SDK includes &lt;code&gt;dfx&lt;/code&gt;, the command-line interface for the SDK. &lt;code&gt;dfx&lt;/code&gt; is used to create, build, deploy, and manage canisters. &lt;code&gt;dfx&lt;/code&gt; also includes a local replica of the ICP blockchain, which can be used for testing and development.&lt;/p&gt;

&lt;p&gt;Install the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-ci&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://internetcomputer.org/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ℹ️ If you are using a machine running Apple silicon, you will need to have Rosetta installed. You can install Rosetta by running &lt;code&gt;softwareupdate --install-rosetta&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clone the example repository
&lt;/h2&gt;

&lt;p&gt;Before you proceed, clone the example repository to your local machine. It includes the full source code for all three canisters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kristoferlund/ic-siwe-react-demo-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, navigate to the project directory and install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;ic-siwe-react-demo-ts
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project is created as a monorepo and consists of two main packages: frontend and backend. The frontend package is the React/Vite application, and the backend package is the Azle TypeScript canister. The SIWE provider does not get a package of its own, as it is a pre-built canister.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ic-siwe-react-demo-ts
├─ packages
│  ├─ backend
│  │  ├─ src
│  │  ├─ backend.did
│  │  ├─ package.json
│  │  ├─ tsconfig.json
│  ├─ frontend
│  │  ├─ src
│  │  ├─ package.json
│  │  ├─ tsconfig.json
│  │  ├─ vite.config.ts
├─ dfx.json
├─ package.json
├─ Makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;dfx.json&lt;/code&gt; configures the project canisters
&lt;/h2&gt;

&lt;p&gt;In the root folder of the project, you will find a file called &lt;code&gt;dfx.json&lt;/code&gt;. This file configures the project canisters and their dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"canisters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ic_siwe_provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"custom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"candid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/kristoferlund/ic-siwe/releases/download/v0.0.4/ic_siwe_provider.did"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"wasm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/kristoferlund/ic-siwe/releases/download/v0.0.4/ic_siwe_provider.wasm.gz"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"backend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"custom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packages/backend/src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"candid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packages/backend/backend.did"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx azle backend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"wasm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".azle/backend/backend.wasm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"gzip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"frontend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"backend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ic_siwe_provider"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm --prefix packages/frontend run build"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output_env_file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".env"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the &lt;code&gt;dfx.json&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ic_siwe_provider&lt;/code&gt; is the prebuilt canister that provides the SIWE authentication method. The &lt;code&gt;candid&lt;/code&gt; and &lt;code&gt;wasm&lt;/code&gt; properties point to the canister's interface definition and WebAssembly binary, respectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;backend&lt;/code&gt; points to the Azle TypeScript canister. The &lt;code&gt;candid&lt;/code&gt; property points to the canister's interface definition, and the &lt;code&gt;main&lt;/code&gt; property points to the canister's entry point. The &lt;code&gt;build&lt;/code&gt; property specifies the command to build the canister, and the &lt;code&gt;wasm&lt;/code&gt; property points to the canister's WebAssembly binary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;frontend&lt;/code&gt; is the assets canister that will host the React/Vite application. The &lt;code&gt;dependencies&lt;/code&gt; property specifies that the canister depends on the &lt;code&gt;backend&lt;/code&gt; and &lt;code&gt;ic_siwe_provider&lt;/code&gt; canisters. The &lt;code&gt;source&lt;/code&gt; property points to the directory containing the built frontend assets, and the &lt;code&gt;build&lt;/code&gt; property specifies the command to build the frontend assets. The canister type, &lt;code&gt;assets&lt;/code&gt;, indicates that the canister will host static assets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configure and deploy the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister
&lt;/h2&gt;

&lt;p&gt;Building composable applications on ICP is easy thanks to WebAssembly! The functionality to provide Ethereum wallet-based authentication is provided by a &lt;a href="https://crates.io/crates/ic_siwe"&gt;Rust library&lt;/a&gt;. If we were to build a Rust canister, we could have chosen to integrate the library directly into the canister. However, we are building a TypeScript canister, so that is not possible. Luckily, there is a pre-built canister available that we can use!&lt;/p&gt;

&lt;p&gt;By adding the pre-built &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister to the &lt;code&gt;dfx.json&lt;/code&gt; of an ICP project, we can quickly enable Ethereum wallet-based authentication. Later we will interact with it from our frontend application as well as from our backend canister.&lt;/p&gt;

&lt;p&gt;Let's start a local replica of ICP blockchain now and deploy the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dfx start &lt;span class="nt"&gt;--background&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have a fully functional local replica of the ICP blockchain running in the background!&lt;/p&gt;

&lt;p&gt;When deploying the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister, we need to provide it with some settings to tell it how to behave. These settings are located in the Makefile of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;create-canisters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    dfx canister create &lt;span class="nt"&gt;--all&lt;/span&gt;

&lt;span class="nl"&gt;deploy-provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    dfx deploy ic_siwe_provider &lt;span class="nt"&gt;--argument&lt;/span&gt; &lt;span class="s2"&gt;"( &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
        record { &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            domain = &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;127.0.0.1&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            uri = &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;http://127.0.0.1:5173&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            salt = &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;some-random-salt&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            chain_id = opt 1; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            scheme = opt &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            statement = opt &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Login to the SIWE/IC demo app&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            sign_in_expires_in = opt 300000000000; /* 5 minutes */ &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            session_expires_in = opt 604800000000000; /* 1 week */ &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            targets = opt vec { &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
                &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="p"&gt;$$(&lt;/span&gt;&lt;span class="s2"&gt;dfx canister id ic_siwe_provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
                &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="p"&gt;$$(&lt;/span&gt;&lt;span class="s2"&gt;dfx canister id backend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
            }; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
        } &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
    )"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To summarize the settings: We tell the provider canister to create sessions that expire after 1 week, and we tell it that the generated identities will be valid for the &lt;code&gt;backend&lt;/code&gt; and &lt;code&gt;ic_siwe_provider&lt;/code&gt; canisters. For more in-depth information about the settings, please refer to the &lt;a href="https://github.com/kristoferlund/ic-siwe/tree/main/packages/ic_siwe_provider"&gt;ic_siwe_provider documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To deploy the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make create-canisters
make deploy-provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command creates all canisters defined in the &lt;code&gt;dfx.json&lt;/code&gt; file. When creating canisters, they are initially empty. The second command deploys the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister and provides it with the settings we defined in the Makefile.&lt;/p&gt;

&lt;p&gt;The output should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployed canisters.
URLs:
  Frontend canister via browser
    frontend: http://127.0.0.1:4943/?canisterId=be2us-64aaa-aaaaa-qaabq-cai
  Backend canister via Candid interface:
    backend: http://127.0.0.1:4943/?canisterId=bw4dl-smaaa-aaaaa-qaacq-cai&amp;amp;id=bd3sg-teaaa-aaaaa-qaaba-cai
    ic_siwe_provider: http://127.0.0.1:4943/?canisterId=bw4dl-smaaa-aaaaa-qaacq-cai&amp;amp;id=br5f7-7uaaa-aaaaa-qaaca-cai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try clicking on the last link to open the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister in your browser. You should see a simple web interface that allows you to interact with the canister.&lt;/p&gt;

&lt;h2&gt;
  
  
  The frontend application
&lt;/h2&gt;

&lt;p&gt;With the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister  in place, now let's take a look at the frontend application. &lt;/p&gt;

&lt;p&gt;There is nothing special about the frontend application, it is 100% a regular React/Vite application. Another great ICP feature is its ability to host web applications built using most frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;main.tsx&lt;/code&gt;:
&lt;/h3&gt;

&lt;p&gt;To setup the frontend application, we need to wrap the &lt;code&gt;&amp;lt;App /&amp;gt;&lt;/code&gt; with a few providers that are used throughout the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;_SERVICE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./declarations/ic_siwe_provider/ic_siwe_provider.did&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;canisterId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idlFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./declarations/ic_siwe_provider/index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WagmiConfig&lt;/span&gt; &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;wagmiConfig&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RainbowKitProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SiweIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;_SERVICE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;canisterId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;canisterId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;idlFactory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;idlFactory&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Actors&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Actors&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;SiweIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RainbowKitProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;WagmiConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Toaster&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start out by wrapping the &lt;code&gt;&amp;lt;App /&amp;gt;&lt;/code&gt; with a &lt;code&gt;WagmiConfig&lt;/code&gt; and &lt;code&gt;RainbowKitProvider&lt;/code&gt;. These providers are used to interact with the Ethereum wallet of the user. &lt;/p&gt;

&lt;p&gt;Find more information RainbowKit here: &lt;a href="https://www.rainbowkit.com/"&gt;RainbowKit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SiweIdentityProvider&lt;/code&gt; is used to interact with the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister and to keep track of the user's identity.&lt;/p&gt;

&lt;p&gt;Note that we are using the &lt;code&gt;idlFactory&lt;/code&gt; and &lt;code&gt;canisterId&lt;/code&gt; from a folder called &lt;code&gt;declarations&lt;/code&gt;. These declarations are generated by the &lt;code&gt;dfx&lt;/code&gt; command line tool. Setting up the &lt;code&gt;SiweIdentityProvider&lt;/code&gt; with this information allows it to interact with the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister in a typesafe way.&lt;/p&gt;

&lt;p&gt;For more details on the setup of the &lt;code&gt;SiweIdentityProvider&lt;/code&gt;, please refer to the &lt;a href="https://github.com/kristoferlund/ic-siwe/tree/main/packages/ic-use-siwe-identity"&gt;ic-use-siwe-identity&lt;/a&gt; documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ic/Actors.tsx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;Actors&lt;/code&gt; component, we wrap our application with yet another provider. This time, it's the &lt;code&gt;ActorProvider&lt;/code&gt; that is used to interact with the backend canister.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;canisterId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idlFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../declarations/backend/index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;_SERVICE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../declarations/backend/backend.did&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Actors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clear&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSiweIdentity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ActorProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;_SERVICE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;canisterId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;canisterId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;actorContext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;idlFactory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;idlFactory&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;ActorProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, we are here using the &lt;code&gt;idlFactory&lt;/code&gt; and &lt;code&gt;canisterId&lt;/code&gt; from the &lt;code&gt;declarations&lt;/code&gt; folder to inform the frontend code about the details of the backend canister.&lt;/p&gt;

&lt;p&gt;In addition to that, note that we are using the &lt;code&gt;useSiweIdentity&lt;/code&gt; hook to get the user's identity. This hook is provided by the &lt;code&gt;ic-use-siwe-identity&lt;/code&gt; package. Connecting the &lt;code&gt;ActorProvider&lt;/code&gt; with the user's identity means it can perform authenticated calls on behalf of the user, once authenticated.&lt;/p&gt;

&lt;p&gt;For more details on the setup of the &lt;code&gt;ActorProvider&lt;/code&gt;, please refer to the &lt;a href="https://github.com/kristoferlund/ic-use-actor"&gt;ic-use-actor&lt;/a&gt; documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;components/profile/EditProfile.tsx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The last frontend component I want to highlight is the &lt;code&gt;EditProfile&lt;/code&gt; component. It is used to create and update user profiles. It is a simple form that allows the user to enter their name and a link to an avatar image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EditProfile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;actor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useActor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save_my_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;avatarUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ok&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle success&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center w-full gap-5"&lt;/span&gt;
          &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submitText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I wanted to show here is the &lt;code&gt;actor.save_my_profile&lt;/code&gt; call. This is a call to the backend canister that will save the user's profile. The &lt;code&gt;actor&lt;/code&gt; object is provided by the &lt;code&gt;ActorProvider&lt;/code&gt;. We access the &lt;code&gt;actor&lt;/code&gt; object using the &lt;code&gt;useActor&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;By connecting the &lt;code&gt;ActorProvider&lt;/code&gt; with the backend canister interfaces, we get a fully typed actor object that we can use to interact with the canister. &lt;/p&gt;

&lt;p&gt;The IC support libraries together with the &lt;code&gt;useActor&lt;/code&gt; hook abstracts away most of the complexity of making authenticated calls to ICP canisters. &lt;/p&gt;

&lt;h3&gt;
  
  
  Build and deploy the frontend canister
&lt;/h3&gt;

&lt;p&gt;Now, let's go ahead and deploy the frontend! The details for building and deploying are defined in the Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;deploy-frontend&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    npm &lt;span class="nb"&gt;install&lt;/span&gt;
    dfx deploy frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing too fancy here, we are simply installing the dependencies and then deploying the frontend canister using the build instructions defined in the &lt;code&gt;dfx.json&lt;/code&gt; file. To build and deploy, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make deploy-frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The backend
&lt;/h2&gt;

&lt;p&gt;Now, let's have a look at the backend canister. The package is setup like a regular TypeScript project, requiring only &lt;a href="https://www.npmjs.com/package/azle"&gt;azle&lt;/a&gt; as a dependency. Nice!&lt;/p&gt;

&lt;p&gt;package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"azle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.20.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ts-node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^10.9.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.2.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building the canister is straight forward using the Azle CLI tool in the root dir of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx azle backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should render an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Building canister backend

Done in 29.40s

🎉 Built canister backend at .azle/backend/backend.wasm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before deploying the backend canister, let's have a look at the code! Every canister has a service interface that defines the methods that can be called on the canister. The service interface is defined in a file called &lt;code&gt;backend.did&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service : (siwe_provider_canister : text) -&amp;gt; {
  "get_my_profile" : () -&amp;gt; (GetMyProfileResponse) query;
  "save_my_profile" : (Name, AvatarUrl) -&amp;gt; (SaveMyProfileResponse);
  "list_profiles" : () -&amp;gt; (ListProfilesResponse) query;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we define three methods: &lt;code&gt;get_my_profile&lt;/code&gt;, &lt;code&gt;save_my_profile&lt;/code&gt;, and &lt;code&gt;list_profiles&lt;/code&gt;. The &lt;code&gt;get_my_profile&lt;/code&gt; and &lt;code&gt;list_profiles&lt;/code&gt; methods are marked as &lt;code&gt;query&lt;/code&gt;, meaning they cannot change the state of the canister. The &lt;code&gt;save_my_profile&lt;/code&gt; method is not marked as &lt;code&gt;query&lt;/code&gt;, meaning it can change the state of the canister.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;index.ts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the entry point of the backend canister. It is the file that will be called when the canister is initialized.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Canister&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;azle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;SiweProviderCanister&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;initializeSiweProviderCanister&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./siwe_provider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;get_my_profile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./service/get_my_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;list_profiles&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./service/list_profiles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;save_my_profile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./service/save_my_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;Canister&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;Principal&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siweProviderPrincipal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;initializeSiweProviderCanister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SiweProviderCanister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siweProviderPrincipal&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;

  &lt;span class="nx"&gt;get_my_profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;save_my_profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;list_profiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, what happens here?&lt;/p&gt;

&lt;p&gt;We begin by importing a &lt;code&gt;Canister&lt;/code&gt; and a &lt;code&gt;Principal&lt;/code&gt; from the &lt;code&gt;azle&lt;/code&gt; package. &lt;code&gt;azle&lt;/code&gt; provides us with all the objects and types we need to interact with ICP, conveniently exported at the top level. &lt;/p&gt;

&lt;p&gt;Exporting a &lt;code&gt;Canister&lt;/code&gt; object is the entry point of the canister. In addition to the three methods defined in the service interface, the backend canister also has an &lt;code&gt;init&lt;/code&gt; method that is called when the canister is initialized. The &lt;code&gt;init&lt;/code&gt; method takes the principal of the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister as an argument and saves this information for later use.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;user_profiles.ts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We need a suitable data structure to store the user profiles. In this file, we define a &lt;code&gt;UserProfile&lt;/code&gt; type and a &lt;code&gt;profileStore&lt;/code&gt;. The &lt;code&gt;profileStore&lt;/code&gt; is a &lt;code&gt;StableBTreeMap&lt;/code&gt; that maps user addresses to user profiles. The name &lt;code&gt;StableBTreeMap&lt;/code&gt; gives a hint that this is a special kind of map. It has access to what is called stable memory, one of the most powerful features of ICP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StableBTreeMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;azle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;avatar_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;profileStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StableBTreeMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stable memory is a feature unique to ICP that provides a long-term, persistent data storage option separate from a canister's heap memory. When a canister is stopped or upgraded, the data stored in stable memory is not cleared or removed. The stable memory is preserved throughout the process while any other WebAssembly state is discarded. &lt;strong&gt;The maximum storage limit for the stable memory of one canister is 400GB!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Note, that is &lt;code&gt;GB&lt;/code&gt; with a &lt;code&gt;G&lt;/code&gt;, not an &lt;code&gt;M&lt;/code&gt; or a &lt;code&gt;K&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;In addition to creating the &lt;code&gt;UserProfile&lt;/code&gt; &lt;strong&gt;object&lt;/strong&gt;, we also define the &lt;code&gt;UserProfile&lt;/code&gt; &lt;strong&gt;type&lt;/strong&gt;. &lt;code&gt;azle&lt;/code&gt; provides us with a utility attribute &lt;code&gt;tsType&lt;/code&gt; that we can use to extract the TypeScript type. Thanks for that!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;save_my_profile.ts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let's also take a closer look at one of the methods defined in the &lt;code&gt;service&lt;/code&gt; interface: &lt;code&gt;save_my_profile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;save_my_profile&lt;/code&gt; is defined as an async method that accepts two arguments: &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;avatar_url&lt;/code&gt;. In addition to saving those two values to the profile, we also want to save the Ethereum address of the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profileStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../user_profiles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Variant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;azle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SIWE_PROVIDER_CANISTER&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../siwe_provider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SaveMyProfileResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Variant&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SaveMyProfileResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;SaveMyProfileResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get_address&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIWE_PROVIDER_CANISTER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toUint8Array&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to get the caller address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save_my_profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;SaveMyProfileResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;avatar_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SaveMyProfileResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;get_address&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;avatar_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;profileStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to save profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend canister has initially no knowledge of the Ethereum address of the user. All it sees is an incoming call from an authenticated IC user. To get the Ethereum address, we need to call the &lt;code&gt;get_address&lt;/code&gt; method on the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister. That is called a cross canister call, and it is done using the &lt;code&gt;ic.call&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Note here, the argument we are passing along to the &lt;code&gt;ic.call&lt;/code&gt; method. We are passing &lt;code&gt;ic.caller().toUint8Array()&lt;/code&gt;, that returns the principal of the caller. If the principal - that is, the user identity - was generated by the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister, the &lt;code&gt;get_address&lt;/code&gt; method will return the Ethereum address of that user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build and deploy the backend canister
&lt;/h3&gt;

&lt;p&gt;We are now ready to deploy the backend canister. The deploy details are defined in the Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;deploy-backend&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    npm &lt;span class="nb"&gt;install&lt;/span&gt;
    dfx deploy backend &lt;span class="nt"&gt;--argument&lt;/span&gt; &lt;span class="s2"&gt;"(principal &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="p"&gt;$$(&lt;/span&gt;&lt;span class="s2"&gt;dfx canister id ic_siwe_provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note here that we are passing the principal of the &lt;code&gt;ic_siwe_provider&lt;/code&gt; canister as an argument to the backend canister. This is the principal that we saved in the &lt;code&gt;init&lt;/code&gt; method of the backend canister.&lt;/p&gt;

&lt;p&gt;To deploy the backend canister, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make deploy-backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  That's it!
&lt;/h2&gt;

&lt;p&gt;With all three canisters deployed, the application is now up and running! Users can connect their Ethereum wallet and create user profiles. The profiles are stored in the backend canister and displayed in the frontend application.&lt;/p&gt;

&lt;p&gt;Access the application by opening the frontend canister in your browser. You can find the URL in the output of the &lt;code&gt;dfx deploy frontend&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;To learn more about how to publish Azle TypeScript canisters to ICP, check out the &lt;a href="https://demergent-labs.github.io/azle/"&gt;Azle documentation&lt;/a&gt;. For more informtion about the features and inner workings of ICP, check out the extensive &lt;a href="https://internetcomputer.org/docs/current/home"&gt;Internet Computer documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we have looked at how to build a cross chain application on ICP using TypeScript and Sign in with Ethereum (SIWE) for authentication. We have seen how to use Azle to write TypeScript canisters and how to use stable memory as a way to store data that survives canister upgrades.&lt;/p&gt;

&lt;p&gt;ICP offers a unique and powerful platform for building decentralized applications. In addition to the features we have looked at in this article, ICP also has a number of additional strengths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;True onchain randomness&lt;/li&gt;
&lt;li&gt;Can handle secrets in a secure way even in a decentralized environment&lt;/li&gt;
&lt;li&gt;Canisters can perform HTTPS outbound requests, effectively making them decentralised oracles&lt;/li&gt;
&lt;li&gt;Canisters can hold BTC natively&lt;/li&gt;
&lt;li&gt;Canisters can hold ETH natively&lt;/li&gt;
&lt;li&gt;Plus much more!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this article has given you a good understanding of how to get started building cross chain applications on ICP. If you have any questions or comments, please post them in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  💜 Happy coding!
&lt;/h2&gt;

</description>
      <category>ethereum</category>
      <category>smartcontract</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>Publish an Astro website on the Internet Computer (ICP)</title>
      <dc:creator>Kristofer</dc:creator>
      <pubDate>Thu, 15 Feb 2024 09:49:14 +0000</pubDate>
      <link>https://forem.com/kristoferlund/publish-an-astro-website-on-the-internet-computer-icp-2h11</link>
      <guid>https://forem.com/kristoferlund/publish-an-astro-website-on-the-internet-computer-icp-2h11</guid>
      <description>&lt;p&gt;&lt;strong&gt;A step-by-step guide to deploying a static website to ICP and hosting it on a custom domain.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://internetcomputer.org/"&gt;Internet Computer&lt;/a&gt; (ICP) is a blockchain-based network that can host programs and data in the form of smart contracts, perform computations on smart contracts in a secure and trustworthy way, and scale infinitely. &lt;strong&gt;Not only can the ICP host smart contracts, but it can also host web pages.&lt;/strong&gt; This means that you can open canister smart contracts directly in your browser just like regular websites.&lt;/p&gt;

&lt;p&gt;In this article, we will go through the process of deploying a static website to the ICP. We will build the website using &lt;a href="https://astro.build/"&gt;Astro&lt;/a&gt; and publish it using the &lt;code&gt;dfx&lt;/code&gt; command-line tool that comes with the &lt;a href="https://github.com/dfinity/sdk"&gt;IC SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Astro with the Automatic CLI
&lt;/h2&gt;

&lt;p&gt;Astro is just great for building content-driven websites like blogs, marketing, and e-commerce. It is super fast, has great support for MDX, TailwindCSS, and more.&lt;/p&gt;

&lt;p&gt;To get started, use the Astro CLI. The CLI will guide you through the process of setting up a new project and installing the necessary dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create astro@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be prompted to answer a few questions about your project. Choose the &lt;strong&gt;blog template&lt;/strong&gt;. Once you have answered the questions, the CLI will create a new project and install the necessary dependencies.&lt;/p&gt;

&lt;p&gt;If you are new to Astro, please see the full &lt;a href="https://docs.astro.build/en/install/auto/"&gt;Astro installation instructions&lt;/a&gt; before proceeding. If you rather prefer copying the code for this project, you can &lt;a href="https://github.com/kristoferlund/blog"&gt;find it on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make sure the project works
&lt;/h2&gt;

&lt;p&gt;Before proceeding, take your new Astro project for a spin and ensure that it works as expected. Navigate to the project directory and start the development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install the IC SDK
&lt;/h2&gt;

&lt;p&gt;Once you have a working Astro project, you can install the &lt;a href="https://github.com/dfinity/sdk"&gt;IC SDK&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-ci&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://internetcomputer.org/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The IC SDK is a software development kit used for creating and managing canister smart contracts on the ICP blockchain. The IC SDK supports &lt;a href="https://internetcomputer.org/docs/current/developer-docs/backend/choosing-language"&gt;Motoko&lt;/a&gt; and &lt;a href="https://internetcomputer.org/docs/current/developer-docs/backend/choosing-language"&gt;Rust&lt;/a&gt; programming languages by default, but &lt;a href="https://internetcomputer.org/docs/current/developer-docs/backend/choosing-language"&gt;developers can use other languages as well&lt;/a&gt;. In addition to building custom canister smart contracts, the IC SDK also supports deploying static website assets, which is what we will be doing in this article.&lt;/p&gt;

&lt;p&gt;The IC SDK includes &lt;code&gt;dfx&lt;/code&gt;, the command-line interface for the SDK. &lt;code&gt;dfx&lt;/code&gt; is used to create, build, deploy, and manage canister smart contracts. &lt;code&gt;dfx&lt;/code&gt; also includes a local replica of the ICP blockchain, which can be used for testing and development.&lt;/p&gt;

&lt;p&gt;If you are using a machine running Apple silicon, you will need to have Rosetta installed. You can install Rosetta by running &lt;code&gt;softwareupdate --install-rosetta&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a dfx.json file
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;dfx.json&lt;/code&gt; file is the main configuration file for ICP projects. It contains key settings that are required to build, deploy, and manage ICP applications. &lt;/p&gt;

&lt;p&gt;Create a new file called &lt;code&gt;dfx.json&lt;/code&gt; in the root of your project. Add the following content to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"canisters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"blog"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm run build"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the settings in the &lt;code&gt;dfx.json&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;canisters&lt;/code&gt;: This is an object that contains the configuration for each canister smart contract in the project. In this case, there is only one canister called &lt;code&gt;blog&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;source&lt;/code&gt;: This is an array of directories that contain the source code for the canister. In this case, the &lt;code&gt;dist&lt;/code&gt; directory contains the compiled Astro website.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt;: This is the type of canister. In this case, the canister is of type &lt;code&gt;assets&lt;/code&gt;, which means it will host static assets like HTML, CSS, and JavaScript files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build&lt;/code&gt;: This is an array of commands that will be run to build the canister. In this case, the &lt;code&gt;npm run build&lt;/code&gt; command will be run to build the Astro website.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Start the local replica
&lt;/h2&gt;

&lt;p&gt;Adding one configuration file to your Astro project, that's it! This is the only configuration you need to deploy a static website to the ICP. To try it out, now start the local replica of the ICP blockchain.&lt;/p&gt;

&lt;p&gt;In a separate terminal, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dfx start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy the canister
&lt;/h2&gt;

&lt;p&gt;Now that the local replica is running, you can deploy the canister to the ICP. Run the following command to deploy the canister:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dfx deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;dfx deploy&lt;/code&gt; command will build the canister using the &lt;code&gt;npm run build&lt;/code&gt; command, and then deploy the canister to the local replica. Once the deployment is complete, you will see a message with the canister ID and the URL where the canister is hosted.&lt;/p&gt;

&lt;p&gt;You should see the first page of your website loading without any issues.&lt;/p&gt;

&lt;p&gt;Please note that clicking on any links will not work as the local replica does not support routing. During development, you can test the website by running &lt;code&gt;npm run dev&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy to the IC
&lt;/h2&gt;

&lt;p&gt;Deploying to the local replica is great for testing and development, but to make the website accessible to the public, you need to deploy it to the ICP mainnet.&lt;/p&gt;

&lt;p&gt;Deploying to mainnet uses the same &lt;code&gt;dfx deploy&lt;/code&gt; command, but now with the &lt;code&gt;--network&lt;/code&gt; flag set to &lt;code&gt;ic&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dfx deploy &lt;span class="nt"&gt;--network&lt;/span&gt; ic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try this now, you will get an error message. You need to have a IC developer account and acquire "cycles" before you can deploy to the ICP mainnet.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a developer account
&lt;/h3&gt;

&lt;p&gt;On ICP developers accounts, or &lt;strong&gt;identities&lt;/strong&gt;, use a private/public key pair for authentication. Accounts are identified by a &lt;strong&gt;principal&lt;/strong&gt; which is a generic identifier value that is used for users, canisters, and potentially other future concepts. Each developer account's principal value is derived from the account's public key from the private/public key pair.&lt;/p&gt;

&lt;p&gt;To setup a developer account, follow these steps: &lt;a href="https://internetcomputer.org/docs/current/developer-docs/setup/accounts"&gt;Creating a developer account&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Aquire cycles
&lt;/h3&gt;

&lt;p&gt;ICP operates on a global network of nodes maintained by independent providers, who are compensated monthly in ICP tokens for their expenses like hardware and electricity. Canister smart contracts on the protocol pay for their resource usage (like storage and compute) in cycles, not in ICP tokens. These cycles, typically provided by the canister's developer, deplete with use and can be replenished by converting and burning ICP tokens.&lt;/p&gt;

&lt;p&gt;You can get cycles for free for testing and development purposes! &lt;br&gt;&lt;a href="https://internetcomputer.org/docs/current/developer-docs/setup/cycles/cycles-faucet"&gt;Getting started with free cycles&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Deploy!
&lt;/h3&gt;

&lt;p&gt;Once setup with a developer account and cycles, you can now deploy the website to the ICP mainnet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dfx deploy &lt;span class="nt"&gt;--network&lt;/span&gt; ic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;dfx deploy&lt;/code&gt; command will build the canister using the &lt;code&gt;npm run build&lt;/code&gt; command, and then deploy the canister to the ICP mainnet. Once the deployment is complete, you will see a message with the canister ID and the URL where the canister is hosted. &lt;/p&gt;

&lt;p&gt;The address where this website is hosted is:&lt;br&gt; &lt;a href="https://avwrm-5iaaa-aaaal-qdhcq-cai.icp0.io"&gt;https://avwrm-5iaaa-aaaal-qdhcq-cai.icp0.io&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure DNS
&lt;/h2&gt;

&lt;p&gt;Being able to access the website using the canister ID is great for testing and development, but it is not very user-friendly. To make the website more accessible to the public, wouldn't it be great if we could use a custom domain name instead?&lt;/p&gt;

&lt;p&gt;Luckily, ICP supports custom domain names for canisters. You can either register the domain with the boundary nodes routing traffic to the canister, or you can host the domain on your own infrastructure. I chose the former (easier) option and configured the domain &lt;a href="https://kristoferlund.se"&gt;kristoferlund.se&lt;/a&gt; to point to the boundry nodes.&lt;/p&gt;

&lt;p&gt;Configuring the domain name involves creating three DNS records: an &lt;code&gt;A&lt;/code&gt; record, a &lt;code&gt;TXT&lt;/code&gt; record, and a &lt;code&gt;CNAME&lt;/code&gt; record. The exact steps for configuring DNS are layed out in the ICP documentation: &lt;a href="https://internetcomputer.org/docs/current/developer-docs/production/custom-domain"&gt;Using custom domains&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The DNS setup involves creating a &lt;code&gt;.ic-assets.json&lt;/code&gt; configuration file. For an Astro website, this file needs to be placed in the &lt;code&gt;public&lt;/code&gt; directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;That's it! You have successfully deployed an Astro website to the ICP. The website is now accessible to the public using a custom domain name.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>blockchain</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
