# Analog 激励测试网教程(更新合约部署）

By [0xRick](https://paragraph.com/@0xb95) · 2024-05-05

---

简介
--

Analog 是一个完全去中心化的第 0 层平台，用于通过时间证明共识机制传达经过验证的事件数据。该平台的核心是 tesseracts 和时间节点，它们可以从主权链私下获取和确认事件数据，允许不同的生态系统使用相同的语言。 Analog旨在引入无需信任的全链互操作性，允许开发人员通过通用协议和API轻松构建他们的应用程序。 Analog 还推出了一种新颖、超快的 PoT 协议，该协议在时间链上创建可验证的事件数据，允许 DApp 开发人员构建下一代基于事件的应用程序。

Twitter
-------

Discord
-------

[

Join the Analog (Official) Discord Server!
------------------------------------------

The Liquidity Hub for Autonomous Chains, powered by our L0 Timechain. | 305682 members

https://discord.com

![](https://storage.googleapis.com/papyrus_images/abb2dfe3c93ec3e8c998f2ad4feba765e3762c70c59fc8796be28a5a4b9c81f0.jpg)

](https://discord.gg/analog)

融资情况
----

Analog完成了由Tribe Capital领投，NGC Ventures、Wintermute、GSR、NEAR、Orange DAO、Mike Novogratz 的另类资产管理公司 Samara Asset Group、Balaji Srinivasan 等参投的1600万美元种子轮及战略轮融资。

空投预期
----

代币分配：ANLOG的总供应量上限为90,579,710。总供应量的一定比例将在主网启动时铸造，剩余的代币将在未来几个月内归属，并按以下方式分发：

种子轮 26.8% 线性分发27个月

机构投资#1 1.9% 线性分发24个月

机构投资#2 0.5% 线性分发24个月

机构投资#3 0.6% 线性分发18个月

机构投资#4 0.5% 线性分发18个月

私募 10.1% 线性分发24个月

战略投资 3.7% 线性分发18个月

团队/顾问 15.4%

资金 14.6%

社区 26%

\-市场 4.5%

**\-空投 2%**

\-公售 5%

\-剩余 14.5%

原文地址：

[

Analog Tokenomics v2.0.docx
---------------------------

This document outlines the key implementation details, in particular, the token economics, or tokenomics, of the Analog. Analog aims to unite autonomous chains by providing interoperability, liquidity, and automated trading. This allows developers and users to leverage individual blockchain strengths within a unified ecosystem.

http://docs.google.com



](https://docs.google.com/document/d/e/2PACX-1vRCpMd7VmDxqGYXYZfj-1RyHdWRU6DfBf1tTad4vlpmmvp4Coavwh9mmT42Te665A/pub)

交互准备
----

下载安装浏览器钱包

**1.SubWallet（推荐）**

[

SubWallet - Polkadot Wallet - Chrome Web Store
----------------------------------------------

Comprehensive Web3 wallet solution for Polkadot, Substrate & Ethereum ecosystems

https://chromewebstore.google.com

![](https://storage.googleapis.com/papyrus_images/46407e0dedddef00a986ba12ad3567d10ffd6336b076e5e4fe7a41903fe49111.jpg)

](https://chromewebstore.google.com/detail/subwallet-polkadot-wallet/onhogfjeacnfoofkfgppdlbmlmnplgbn)

2.Talisman

[

Talisman Wallet - Chrome Web Store
----------------------------------

Talisman is an open-source crypto wallet that makes web3 simple for beginners and unlocks superpowers for pros.

https://chromewebstore.google.com

![](https://storage.googleapis.com/papyrus_images/8d2069d7bbd071213b25241bd078b5ca35ca4bfd0f88e6d85c179fc09838f5b6.jpg)

](https://chromewebstore.google.com/detail/talisman-ethereum-and-pol/fijngjgcjhjmmpcmkeiomlglpeiijkld)

3.Polkadot.JS

[

polkadot{.js} extension - Chrome Web Store
------------------------------------------

Manage your Polkadot accounts outside of dapps. Injects the accounts and allows signing transactions for a specific account.

https://chromewebstore.google.com

![](https://storage.googleapis.com/papyrus_images/d714ee758fc40432eece17fc9879bd792e367c96a65af0b6da9dbd6a102b8d9d.jpg)

](https://chromewebstore.google.com/detail/polkadot%7Bjs%7D-extension/mopnmbcafieddcagagdcbnhejhlodfdd)

4.Enkrypt

[

Enkrypt: ETH, BTC and Solana Wallet - Chrome Web Store
------------------------------------------------------

The best multichain crypto wallet

https://chromewebstore.google.com

![](https://storage.googleapis.com/papyrus_images/c935883493818b1d199614571b2814c6b60b112c7fa877db67de29aa43efa838.jpg)

](https://chromewebstore.google.com/detail/enkrypt-multichain-crypto/kkpllkodjeloidieedojogacfhpaihoh)

添加网络并领水

以SubWallet钱包为例（建议第二个方法添加）

![](https://storage.googleapis.com/papyrus_images/3fc862382ec80ed18eaa2248bc96fb2e47846874d3d3d50634e182a856f04b95.png)

![](https://storage.googleapis.com/papyrus_images/be11e3c6fd5933779b7688d42d141154423bd3e0de87cd384fac94613f8734a7.png)

![](https://storage.googleapis.com/papyrus_images/a540ab5f1af5a54a0a6bce6fef98def2ab55ddaf409efcf782cc7526cfffa46a.png)

在URL处填写：wss://rpc.testnet.analog.one 然后保存即可

![](https://storage.googleapis.com/papyrus_images/32ca59072e7f320099c5a22927f083d5e80911a93bab1c964dd6cc0b6c4846d9.png)

钱包首页下拉找到添加的代币，进入复制地址

![](https://storage.googleapis.com/papyrus_images/8448e70d4e57a546e82545b25ec9403af5d4a249aed69310486b14ed19db861c.png)

![](https://storage.googleapis.com/papyrus_images/7d8338e58000f18cab2473ae994ef1b29b1d329becfe6b880cb014b9fc6532b7.png)

或者前往（推荐此方法）：

[https://watch.testnet.analog.one/#/](https://watch.testnet.analog.one/#/)

链接钱包

![](https://storage.googleapis.com/papyrus_images/a561ce4ba5bd91a413a765a7e90a62c7c9628a9a659b237e7fa71a6628a4acae.png)

![](https://storage.googleapis.com/papyrus_images/5172f3662ec37f34849b01cf9379795012832452db0d38e16660a0977ceb660a.png)

链接好钱包之后点击右上角的钱包，复制第2个an开头的地址即可

![](https://storage.googleapis.com/papyrus_images/83b7a902485b84f6b872c514d17ad763429a97837904c14ea5b5e8f60111c3ab.png)

前往DC的\*\*#faucet\*\*频道输入：!faucet+钱包地址 领水

![](https://storage.googleapis.com/papyrus_images/a97e8ce1ad9ca2d131b0f4667f126f82ecf981640b70e5ee1f9d423b71a74ea7.png)

交互流程
----

前往

[https://testnet.analog.one/#/?signup&referral=YJCC50](https://testnet.analog.one/#/?signup&referral=YJCC50)

注册账号

![](https://storage.googleapis.com/papyrus_images/8089f3c07e8ee7e676b4481c032257311a6ced4644b077c45d73f49b511540fe.png)

![](https://storage.googleapis.com/papyrus_images/aa07713e192d32fe689f86eba3fa2ad25be1347aa4305607e05c735ca7a6b5e9.png)

绑定EVM钱包

![](https://storage.googleapis.com/papyrus_images/915f48756203301fe743c1aa876da68952a5653d37e133d8812822cfd16260c1.png)

![](https://storage.googleapis.com/papyrus_images/b514a85a3a4b08e8a40a3a5f4f9bf446d0ec0e3420fe4c7c870d6ab40cbf5003.png)

然后点击银河链接，跳转至银河页面，完成社交任务即可

![](https://storage.googleapis.com/papyrus_images/e5ec30be49f94c6d4897fcfe19931f23c3daa879003373d803922d83050f428e.png)

![](https://storage.googleapis.com/papyrus_images/10f90a3d6970f1578b06d66eba9f9c9da81cf6493d7f7fcae1f271037891eb52.png)

完成银河任务之后返回任务页面，Claim积分即可

![](https://storage.googleapis.com/papyrus_images/6f1ada6c22272c42224cd76995a129514a5a8af3dce21cd7cd9a6c5aeaa7899a.png)

WATCH GAME栏任务，需要在有会议和投票的时候才可以参加并获得积分，等待任务不定时开启

![](https://storage.googleapis.com/papyrus_images/0107aef346311e77ff24eb05f6a4d7596794345aa99dd5c75ea76a6776ff9750.png)

![](https://storage.googleapis.com/papyrus_images/506285b99af470ebf3fb04edfc864c79fd66060299bb5583e9040b567d0e4a83.png)

开启WATCH GAME之后，进入，点击START VOTING

![](https://storage.googleapis.com/papyrus_images/1d43841532aa4a95976949aac00b14fc75fa6947adfcb54402b0e103e620a698.png)

任意挑选一个投票

![](https://storage.googleapis.com/papyrus_images/d17ce7daa4f4e053111eae9da26595e3a1041865f1f7e3a7468a98d6d2f410fd.png)

完成之后WATCH GAME栏积分增加10，获胜后可以得到更多积分（建议大家都投票给1号）

![](https://storage.googleapis.com/papyrus_images/0f0926d432b6659b7b76a1a38937b511bb48b6606f88504b7d512fe40a745fba.png)

Developer任务栏
------------

在Quests类目内点击右方的Developer栏

![](https://storage.googleapis.com/papyrus_images/d03cfc60287f73cc669eb3b8587fa9cfc9b8ae28d724d5cf5660684b7ae50711.png)

下来页面，分别连接钱包（Sub和小狐狸）

![](https://storage.googleapis.com/papyrus_images/3b1a55f4a2bf2ecc93f177853b29892495b26b26283612c8168ab8c8e3786650.png)

**Create an API Key**

点击之后跳转页面

![](https://storage.googleapis.com/papyrus_images/39330015d8cad13f2e2a53a0ee413dbab207fe99c3a063a271b21586b7d85f02.png)

点击API Keys，然后选择创建新的API Key

![](https://storage.googleapis.com/papyrus_images/f5c9029c4323ed15e0721b01715bf5efe3b0db91423c467a21b4cb172956d3c5.png)

输入名称并钱包签名，然后Next

![](https://storage.googleapis.com/papyrus_images/f868a76f406f67ea468f571239032377aa0f77f774b92d89779815c9569c1797.png)

创建完成即可

剩下的任务是合约部署和bug反馈这类的开发者任务，能力有限，需要花时间研究，完成后更新

部署一个智能合约
--------

前往Remix

新建一个.sol文件（名字任意）

![](https://storage.googleapis.com/papyrus_images/cd1a33964a3775aaf82b02c89e447a63f8909a948f58f38dd6cf74b1248eed89.png)

![](https://storage.googleapis.com/papyrus_images/0752fee45b0f1504cd3b9cb830d0f734575d209703aa43b6f33feaadb90a6f2f.png)

复制以下代码填入：

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface IGmpReceiver {
        /**
         * @dev Handles the receipt of a single GMP message.
         * The contract must verify the msg.sender, it must be the Gateway Contract address.
         *
         * @param id The EIP-712 hash of the message payload, used as GMP unique identifier
         * @param network The chain_id of the source chain that send the message
         * @param source The pubkey/address which sent the GMP message
         * @param payload The message payload with no specified format
         * @return 32-byte result, which will be stored together with the GMP message
         */
        function onGmpReceived(bytes32 id, uint128 network, bytes32 source, bytes calldata payload)
            external
            payable
            returns (bytes32);
    }
    
    contract Counter is IGmpReceiver {
        // sepolia 0xB5D83c2436Ad54046d57Cd48c00D619D702F3814
        // shibuya 0xF871c929bE8Cd8382148C69053cE5ED1a9593EA7
        address private immutable _gateway;
        uint256 public number;
    
        constructor(address gateway) {
            _gateway = gateway;
        }
    
        function onGmpReceived(bytes32, uint128, bytes32, bytes calldata) external payable override returns (bytes32) {
            require(msg.sender == _gateway, "unauthorized");
            number++;
            return bytes32(number);
        }
    }
    

![](https://storage.googleapis.com/papyrus_images/2b3f9602f358670cf8c40cc2ac891b7cce9f5db8cdcdc23883a3bf9360a9ca22.png)

然后编译合约

![](https://storage.googleapis.com/papyrus_images/8df75cfd869bacba829429fdc5a2e11d666fdb70d28bda898f33a3ee0c336c77.png)

编译完成之后，部署合约

![](https://storage.googleapis.com/papyrus_images/204af34968db8ecac1d71bbddb719bdd909c934722261f5992db396d37b572b2.png)

**Sepolia的gateway地址：**

钱包确认之后部署成功

复制合约地址

![](https://storage.googleapis.com/papyrus_images/a83e9cb031094698cfd55e49f8b07b0ef7e1e0b26db004584efaa26a904971dd.png)

前往

[

Sepolia blockchain explorer - View Sepolia stats | Blockscout
-------------------------------------------------------------

Open-source block explorer by Blockscout. Search transactions, verify smart contracts, analyze addresses, and track network activity. Complete blockchain data and APIs for the Sepolia Explorer network.

https://eth-sepolia.blockscout.com

![](https://storage.googleapis.com/papyrus_images/935635827705cea2b23e09a23bb5cba5148677753b965d9d212798615ec9b83e.png)

](https://eth-sepolia.blockscout.com/)

输入刚刚复制的合约地址搜索并进入

![](https://storage.googleapis.com/papyrus_images/6c0173238b6858cd6082ef24aa968e34272c0e2fe47bad292657edd3fb07d942.png)

下拉页面，点击Contract和Verify & publish

![](https://storage.googleapis.com/papyrus_images/70081ca3a7b47e2d4def07132b0941369644d92e713febd55fea2b9d55733972.png)

跳转页面如截图选择，code处输入以下代码

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    interface IGmpReceiver {
        /**
         * @dev Handles the receipt of a single GMP message.
         * The contract must verify the msg.sender, it must be the Gateway Contract address.
         *
         * @param id The EIP-712 hash of the message payload, used as GMP unique identifier.
         * @param network The chain_id of the source chain that sent the message.
         * @param source The pubkey/address which sent the GMP message.
         * @param payload The message payload with no specified format.
         * @return 32-byte result, which will be stored together with the GMP message.
         */
        function onGmpReceived(bytes32 id, uint128 network, bytes32 source, bytes calldata payload)
            external
            payable
            returns (bytes32);
    }
    
    contract Counter is IGmpReceiver {
        address private immutable _gateway;
        uint256 public number;
    
        constructor(address gateway) {
            _gateway = gateway;
        }
    
        function onGmpReceived(bytes32, uint128, bytes32, bytes calldata) 
            external 
            payable 
            override 
            returns (bytes32) 
        {
            // Verify that the sender is the gateway contract
            require(msg.sender == _gateway, "unauthorized");
            
            // Increment the counter
            number++;
            
            // Return the new value of the counter as a bytes32
            return bytes32(number);
        }
    }
    

![](https://storage.googleapis.com/papyrus_images/9454cac0027e542df2ea79a8d77731b0311a381525018239c5fff4143f8eb4b7.png)

然后前往

[https://watch.testnet.analog.one/#/](https://watch.testnet.analog.one/#/)

点击顶部的Smart Contracts

![](https://storage.googleapis.com/papyrus_images/9ef8657884118dfed6f7d6bd423f75c695d54db8a1f8c28f81336c1cafae6517.png)

弹出窗口，将部署的合约地址复制填入

![](https://storage.googleapis.com/papyrus_images/2ca423cd943e3325be88626d5d8faed0f7ba9bdfa1a163332659d8747015b80f.png)

返回合约部署页面，复制ABI

![](https://storage.googleapis.com/papyrus_images/5881b7194f6aed60a552abd9cc1b736a313dc7b66ce7310e951df6f1fde996b1.png)

然后填入Analog watch的下一步

![](https://storage.googleapis.com/papyrus_images/74a48baede1a6e47ef6d5326f216b94770e402aa022bde523eaa38b12bff3921.png)

勾选后点击List即上传成功

![](https://storage.googleapis.com/papyrus_images/6668a9382e0548661b9242dd3c040e632c248f197e38ac5708083a7ba56564da.png)

![](https://storage.googleapis.com/papyrus_images/1f2285b6cd64969a46de4687746809b4523f8b0377363c241c763ec15ad4bc5e.png)

**Build and deploy a View（7月更新）**

点击个人主页，View Builder

![](https://storage.googleapis.com/papyrus_images/c63b701f06ad324196f1da6150b832ec3a01191d2c643c7549034bbcf9ac1f2a.png)

搜索uniswap、curvefi这一类别人建设好的代码项目(也可选择 UniSwapV3WETHUSDT - slot0 函数 、CurvefiUSDTWBTCWETH - get\_virtual\_price、及 get\_dy函数 .)

修改一下数值运行成功即可

![](https://storage.googleapis.com/papyrus_images/63924308d340ddd328d2cbfc1fa77d0bee0496ddfe362dd5cb97aad309d25c0a.png)

![](https://storage.googleapis.com/papyrus_images/f5921d7797909e573a30200ba692abc87eb64b3da16383eb2d9db475608b3b42.png)

![](https://storage.googleapis.com/papyrus_images/15bb80f6860035bed5562425ead0539f07b6493fd2f92fa3a6e25b5ae8407a0b.png)

![](https://storage.googleapis.com/papyrus_images/0191febf11eb32e9cd6e7e48d49201330988e330fd13c6ceb9c21eab3426032f.png)

完成之后，进入项目，向项目捐款

![](https://storage.googleapis.com/papyrus_images/c350b264902031f689d0e14f0d90dd1d4eb77525f1325336b63106edb9949a58.png)

![](https://storage.googleapis.com/papyrus_images/96b2806002e90549a27242115dc75c90de694a38bcba7a97db587372ecd46e58.png)

**Sponsor/Fund a Unique View**

前往

[https://watch.testnet.analog.one/#/library](https://watch.testnet.analog.one/#/library)

点击任意项目进入（上一步完成，也可以进入自己的项目）

![](https://storage.googleapis.com/papyrus_images/f3c0b79c6bd298ae0de795023d18dc0b4db676e220430715d4f77456658e00b3.png)

点击Add Funds捐赠一部分测试币即可

![](https://storage.googleapis.com/papyrus_images/3bffad8bd0ef421be7c0eff1999018376e0e776406649bf654ab3df66ae545b2.png)

![](https://storage.googleapis.com/papyrus_images/45b188a7f23ba6343452c40f69f75a4b91110bd6e8cff546fabdb9d4cccbafcd.png)

**Query a Unique View**

需要的代码知识较复杂和问题较多，可看KOL @ouyoung11 的教程

[![User Avatar](https://storage.googleapis.com/papyrus_images/20a109ca3bc342404890fe66ddbcacff99f0557d3e3a52962a4bc6fc0a7e5076.jpg)](https://twitter.com/ouyoung11)

[oooooyoung(吸吸喜气欧皇版)](https://twitter.com/ouyoung11)

[@ouyoung11](https://twitter.com/ouyoung11)

[![Twitter Logo](https://paragraph.com/editor/twitter/logo.png)](https://twitter.com/ouyoung11/status/1787029033638871339)

(7/) Query a Unique View 查询唯一视图 教程篇1  
  
这一步其实需要写代码，用 analog watch sdk 来完成，我这里写了个模版，大伙根据我的代码模版参考下面的教程完成即可![👇](https://abs-0.twimg.com/emoji/v2/72x72/1f447.png)：  
  
![1️⃣](https://abs-0.twimg.com/emoji/v2/72x72/31-20e3.png) 进入 [codesandbox.io/p/devbox/analo…](https://t.co/WdSyrIuqtP) 并fork我的代码模版 （没注册 codesandbox的可能需要注册下，是在线运行代码的平台）  
  
![2️⃣](https://abs-0.twimg.com/emoji/v2/72x72/32-20e3.png)

![](https://storage.googleapis.com/papyrus_images/80e169fd6a6f7edb95b34dc74f20dd29b574f48f4a0125aa56a004995cba3a37.jpg)

 [![Like Icon](https://paragraph.com/editor/twitter/heart.png) 8](https://twitter.com/ouyoung11/status/1787029033638871339)[

2:58 AM • May 5, 2024

](https://twitter.com/ouyoung11/status/1787029033638871339)

GMP
---

**Build and deploy a smart contract using Analog GMP interfaces on Sepolia and Shibuya Testnet**

复制创建的智能合约地址然后Claim即可

![](https://storage.googleapis.com/papyrus_images/900ea2548c0cd9d290c7bb698ac0b298fac75f50eb914e38125c1e328bf49f86.png)

**Send a message using a GMP gateway contract**

前往

[https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract](https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract)

连接小狐狸钱包

![](https://storage.googleapis.com/papyrus_images/abbe53d5d78cfd27fa7662bcd0f94d8c545eae67a0ac28ea734e1d4cb02b9e27.png)

然后拉开第三项填入如图数值

地址：

0xB5D83c2436Ad54046d57Cd48c00D619D702F3814

![](https://storage.googleapis.com/papyrus_images/bea2e391ec37ef446bdb4f240fb3a1e63c80844945469834c100b537ed5f9f2b.png)

钱包确认之后view跳转页面复制tx

![](https://storage.googleapis.com/papyrus_images/352d351a2b9caa3e19979cfc1a089b074413822d81d46728c52aefab14d8a545.png)

![](https://storage.googleapis.com/papyrus_images/522edcd961bd5c97da54c9f398ccff3674abdb832469ad3a2b5a5a74f96afbd4.png)

然后返回任务页面填入并Claim

![](https://storage.googleapis.com/papyrus_images/f8d56e7db7b8820298d98ebc1a8d881f5fabe525a2e53a79890654a1231591c7.png)

DMAIL任务

点击DMAIL下的链接，跳转至DMAIL

![](https://storage.googleapis.com/papyrus_images/cdef1aadb68d0e46625d6dbbbf9ee8f208f98e653fac8fcf0a06faab7f622712.png)

使用Gmail登录即可

![](https://storage.googleapis.com/papyrus_images/78c2044cbc0e9299027e6f7d858fc73346fbae089469cb8c3bdc5f79f14a6d75.png)

**Embark on the Analog Incentivized Odyssey!**

前往

[https://www.intract.io/quest/667405d2e1972009849c96dc?utm\_source=dashboard](https://www.intract.io/quest/667405d2e1972009849c96dc?utm_source=dashboard)

完成基础社交任务即可，都可以假过，需要MATIC Gas（7月30号结束）

![](https://storage.googleapis.com/papyrus_images/8af22fb73a19a79f1973097a3a627b01263e3154fb2b84681f787403536e59ec.png)

**TALISMAN**

使用Talisman钱包（如果之前使用的其他钱包，可以将助记词导入然后再连接）

然后完成任务

[

Talisman Quests
---------------

Earn Airdrops with the Talisman wallet: An intuitive and user-friendly wallet built for the multi-chain world.

https://quest.talisman.xyz



](https://quest.talisman.xyz/)

任务页面拉至底部

分别进入两个Analog任务

![](https://storage.googleapis.com/papyrus_images/8c188b16a9fe6cca8044e1c82335cefff8b161d251745bead5afd3eee7246c5d.png)

点击之后，分别完成资助项目和转账的任务就可以Claim积分了

**GMP Sepolia+shibuya测试网新代码**

同样的，前往Remix：

和之前一样，创建.sol文件，不过这次需要创建3个

1.**BranchlessMath.sol**

    // SPDX-License-Identifier: MIT
    // Analog's Contracts (last updated v0.1.0) (src/utils/BranchlessMath.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * 
    @dev
     Utilities for branchless operations, useful when a constant gas cost is required.
     */
    library BranchlessMath {
        /**
         * 
    @dev
     Returns the smallest of two numbers.
         */
        function min(uint256 x, uint256 y) internal pure returns (uint256) {
            return select(x < y, x, y);
        }
    
        /**
         * 
    @dev
     Returns the largest of two numbers.
         */
        function max(uint256 x, uint256 y) internal pure returns (uint256) {
            return select(x > y, x, y);
        }
    
        /**
         * 
    @dev
     If `condition` is true returns `a`, otherwise returns `b`.
         */
        function select(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
            unchecked {
                // branchless select, works because:
                // b ^ (a ^ b) == a
                // b ^ 0 == b
                //
                // This is better than doing `condition ? a : b` because:
                // - Consumes less gas
                // - Constant gas cost regardless the inputs
                // - Reduces the final bytecode size
                return b ^ ((a ^ b) * toUint(condition));
            }
        }
    
        /**
         * 
    @dev
     If `condition` is true returns `a`, otherwise returns `b`.
         */
        function select(bool condition, address a, address b) internal pure returns (address) {
            return address(uint160(select(condition, uint256(uint160(a)), uint256(uint160(b)))));
        }
    
        /**
         * 
    @dev
     If `condition` is true return `value`, otherwise return zero.
         */
        function selectIf(bool condition, uint256 value) internal pure returns (uint256) {
            unchecked {
                return value * toUint(condition);
            }
        }
    
        /**
         * 
    @dev
     Unsigned saturating addition, bounds to UINT256 MAX instead of overflowing.
         * equivalent to:
         * uint256 r = x + y;
         * return r >= x ? r : UINT256_MAX;
         */
        function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256) {
            unchecked {
                x = x + y;
                y = 0 - toUint(x < y);
                return x | y;
            }
        }
    
        /**
         * 
    @dev
     Unsigned saturating subtraction, bounds to zero instead of overflowing.
         * equivalent to: x > y ? x - y : 0
         */
        function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
            unchecked {
                // equivalent to: a > b ? a - b : 0
                return (a - b) * toUint(a > b);
            }
        }
    
        /**
         * 
    @dev
     Unsigned saturating multiplication, bounds to `2 ** 256 - 1` instead of overflowing.
         */
        function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
            unchecked {
                uint256 c = a * b;
                bool success;
                assembly {
                    // Only true when the multiplication doesn't overflow
                    // (c / a == b) || (a == 0)
                    success := or(eq(div(c, a), b), iszero(a))
                }
                return c | (toUint(success) - 1);
            }
        }
    
        /**
         * 
    @dev
     Unsigned saturating division, bounds to UINT256 MAX instead of overflowing.
         */
        function saturatingDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
            assembly {
                r := div(x, y)
            }
        }
    
        /**
         * 
    @dev
     Returns the ceiling of the division of two numbers.
         *
         * This differs from standard division with `/` in that it rounds towards infinity instead
         * of rounding towards zero.
         */
        function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
            unchecked {
                // The following calculation ensures accurate ceiling division without overflow.
                // Since a is non-zero, (a - 1) / b will not overflow.
                // The largest possible result occurs when (a - 1) / b is type(uint256).max,
                // but the largest value we can obtain is type(uint256).max - 1, which happens
                // when a = type(uint256).max and b = 1.
                return selectIf(a > 0, ((a - 1) / b + 1));
            }
        }
    
        /**
         * 
    @dev
     Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
         */
        function toUint(bool b) internal pure returns (uint256 u) {
            /// 
    @solidity
     memory-safe-assembly
            assembly {
                u := iszero(iszero(b))
            }
        }
    
        /**
         * 
    @dev
     Cast an address to uint256
         */
        function toUint(address addr) internal pure returns (uint256) {
            return uint256(uint160(addr));
        }
    }
    

2.**Primitives.sol**

    // SPDX-License-Identifier: MIT
    // Analog's Contracts (last updated v0.1.0) (src/Primitives.sol)
    
    pragma solidity >=0.8.0;
    
    import {BranchlessMath} from "./BranchlessMath.sol";
    
    /**
     * 
    @dev
     GmpSender is the sender of a GMP message
     */
    type GmpSender is bytes32;
    
    /**
     * 
    @dev
     Tss public key
     * 
    @param
     yParity public key y-coord parity, the contract converts it to 27/28
     * 
    @param
     xCoord affine x-coordinate
     */
    struct TssKey {
        uint8 yParity;
        uint256 xCoord;
    }
    
    /**
     * 
    @dev
     Schnorr signature.
     * OBS: what is actually signed is: keccak256(abi.encodePacked(R, parity, px, nonce, message))
     * Where `parity` is the public key y coordinate stored in the contract, and `R` is computed from `e` and `s` parameters.
     * 
    @param
     xCoord public key x coordinates, y-parity is stored in the contract
     * 
    @param
     e Schnorr signature e component
     * 
    @param
     s Schnorr signature s component
     */
    struct Signature {
        uint256 xCoord;
        uint256 e;
        uint256 s;
    }
    
    /**
     * 
    @dev
     GMP payload, this is what the timechain creates as task payload
     * 
    @param
     source Pubkey/Address of who send the GMP message
     * 
    @param
     srcNetwork Source chain identifier (for ethereum networks it is the EIP-155 chain id)
     * 
    @param
     dest Destination/Recipient contract address
     * 
    @param
     destNetwork Destination chain identifier (it's the EIP-155 chain_id for ethereum networks)
     * 
    @param
     gasLimit gas limit of the GMP call
     * 
    @param
     salt Message salt, useful for sending two messages with same content
     * 
    @param
     data message data with no specified format
     */
    struct GmpMessage {
        GmpSender source;
        uint16 srcNetwork;
        address dest;
        uint16 destNetwork;
        uint256 gasLimit;
        uint256 salt;
        bytes data;
    }
    
    /**
     * 
    @dev
     Message payload used to revoke or/and register new shards
     * 
    @param
     revoke Shard's keys to revoke
     * 
    @param
     register Shard's keys to register
     */
    struct UpdateKeysMessage {
        TssKey[] revoke;
        TssKey[] register;
    }
    
    /**
     * 
    @dev
     Message payload used to revoke or/and register new shards
     * 
    @param
     revoke Shard's keys to revoke
     * 
    @param
     register Shard's keys to register
     */
    struct Network {
        uint16 id;
        address gateway;
    }
    
    /**
     * 
    @dev
     Status of a GMP message
     */
    enum GmpStatus {
        NOT_FOUND,
        SUCCESS,
        REVERT,
        INSUFFICIENT_FUNDS,
        PENDING
    }
    
    /**
     * 
    @dev
     EIP-712 utility functions for primitives
     */
    library PrimitiveUtils {
        /**
         * 
    @dev
     GMP message EIP-712 Type Hash.
         * Declared as raw value to enable it to be used in inline assembly
         * keccak256("GmpMessage(bytes32 source,uint16 srcNetwork,address dest,uint16 destNetwork,uint256 gasLimit,uint256 salt,bytes data)")
         */
        bytes32 internal constant GMP_MESSAGE_TYPE_HASH = 0xeb1e0a6b8c4db87ab3beb15e5ae24e7c880703e1b9ee466077096eaeba83623b;
    
        function toAddress(GmpSender sender) internal pure returns (address) {
            return address(uint160(uint256(GmpSender.unwrap(sender))));
        }
    
        function toSender(address addr, bool isContract) internal pure returns (GmpSender) {
            uint256 sender = BranchlessMath.toUint(isContract) << 160 | uint256(uint160(addr));
            return GmpSender.wrap(bytes32(sender));
        }
    
        // computes the hash of an array of tss keys
        function eip712hash(TssKey memory tssKey) internal pure returns (bytes32) {
            return keccak256(abi.encode(keccak256("TssKey(uint8 yParity,uint256 xCoord)"), tssKey.yParity, tssKey.xCoord));
        }
    
        // computes the hash of an array of tss keys
        function eip712hash(TssKey[] memory tssKeys) internal pure returns (bytes32) {
            bytes memory keysHashed = new bytes(tssKeys.length * 32);
            uint256 ptr;
            assembly {
                ptr := keysHashed
            }
            for (uint256 i = 0; i < tssKeys.length; i++) {
                bytes32 hash = eip712hash(tssKeys[i]);
                assembly {
                    ptr := add(ptr, 32)
                    mstore(ptr, hash)
                }
            }
    
            return keccak256(keysHashed);
        }
    
        // computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer
        function eip712hash(UpdateKeysMessage memory message) internal pure returns (bytes32) {
            return keccak256(
                abi.encode(
                    keccak256("UpdateKeysMessage(TssKey[] revoke,TssKey[] register)TssKey(uint8 yParity,uint256 xCoord)"),
                    eip712hash(message.revoke),
                    eip712hash(message.register)
                )
            );
        }
    
        function eip712TypedHash(UpdateKeysMessage memory message, bytes32 domainSeparator)
            internal
            pure
            returns (bytes32)
        {
            return _computeTypedHash(domainSeparator, eip712hash(message));
        }
    
        function eip712hash(GmpMessage memory message) internal pure returns (bytes32 id) {
            bytes memory data = http://message.data;
            /// 
    @solidity
     memory-safe-assembly
            assembly {
                // keccak256(http://message.data)
                id := keccak256(add(data, 32), mload(data))
    
                // now compute the GmpMessage Type Hash without memory copying
                let offset := sub(message, 32)
                let backup := mload(offset)
                {
                    mstore(offset, GMP_MESSAGE_TYPE_HASH)
                    {
                        let offset2 := add(offset, 0xe0)
                        let backup2 := mload(offset2)
                        mstore(offset2, id)
                        id := keccak256(offset, 0x100)
                        mstore(offset2, backup2)
                    }
                }
                mstore(offset, backup)
            }
        }
    
        function encodeCallback(GmpMessage calldata message, bytes32 domainSeparator)
            internal
            pure
            returns (bytes32 messageHash, bytes memory r)
        {
            bytes calldata data = http://message.data;
            /// 
    @solidity
     memory-safe-assembly
            assembly {
                r := mload(0x40)
    
                // GmpMessage Type Hash
                mstore(add(r, 0x0004), GMP_MESSAGE_TYPE_HASH)
                mstore(add(r, 0x0024), calldataload(add(message, 0x00))) // message.source
                mstore(add(r, 0x0044), calldataload(add(message, 0x20))) // message.srcNetwork
                mstore(add(r, 0x0064), calldataload(add(message, 0x40))) // message.dest
                mstore(add(r, 0x0084), calldataload(add(message, 0x60))) // message.destNetwork
                mstore(add(r, 0x00a4), calldataload(add(message, 0x80))) // message.gasLimit
                mstore(add(r, 0x00c4), calldataload(add(message, 0xa0))) // message.salt
    
                // Copy http://message.data to memory
                let size := data.length
                mstore(add(r, 0x0104), size) // http://message.data length
                calldatacopy(add(r, 0x0124), data.offset, size) // http://message.data
    
                // Computed GMP Typed Hash
                messageHash := keccak256(add(r, 0x0124), size) // keccak(http://message.data)
                mstore(add(r, 0x00e4), messageHash)
                messageHash := keccak256(add(r, 0x04), 0x0100) // GMP eip712 hash
                mstore(0, 0x1901)
                mstore(0x20, domainSeparator)
                mstore(0x40, messageHash) // this will be restored at the end of this function
                messageHash := keccak256(0x1e, 0x42) // GMP Typed Hash
    
                // onGmpReceived
                size := and(add(size, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)
                size := add(size, 0xa4)
                mstore(add(r, 0x0064), 0x01900937) // selector
                mstore(add(r, 0x0060), size) // length
                mstore(add(r, 0x0084), messageHash) // GMP Typed Hash
                mstore(add(r, 0x00a4), calldataload(add(message, 0x20))) // http://msg.network
                mstore(add(r, 0x00c4), calldataload(add(message, 0x00))) // msg.source
                mstore(add(r, 0x00e4), 0x80) // http://msg.data offset
    
                size := and(add(size, 31), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)
                size := add(size, 0x60)
                mstore(0x40, add(add(r, size), 0x40))
                r := add(r, 0x60)
            }
        }
    
        function eip712TypedHash(GmpMessage memory message, bytes32 domainSeparator)
            internal
            pure
            returns (bytes32 messageHash)
        {
            messageHash = eip712hash(message);
            messageHash = _computeTypedHash(domainSeparator, messageHash);
        }
    
        function _computeTypedHash(bytes32 domainSeparator, bytes32 messageHash) private pure returns (bytes32 r) {
            /// 
    @solidity
     memory-safe-assembly
            assembly {
                mstore(0, 0x1901000000000000000000000000000000000000000000000000000000000000)
                mstore(0x02, domainSeparator)
                mstore(0x22, messageHash)
                r := keccak256(0, 0x42)
                mstore(0x22, 0)
            }
        }
    }
    

3.**IGateway.sol**

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface IGmpReceiver {
        /**
         * @dev Handles the receipt of a single GMP message.
         * The contract must verify the msg.sender, it must be the Gateway Contract address.
         *
         * @param id The EIP-712 hash of the message payload, used as GMP unique identifier
         * @param network The chain_id of the source chain that send the message
         * @param source The pubkey/address which sent the GMP message
         * @param payload The message payload with no specified format
         * @return 32-byte result, which will be stored together with the GMP message
         */
        function onGmpReceived(bytes32 id, uint128 network, bytes32 source, bytes calldata payload)
            external
            payable
            returns (bytes32);
    }
    
    contract Counter is IGmpReceiver {
        // sepolia 0xB5D83c2436Ad54046d57Cd48c00D619D702F3814
        // shibuya 0xF871c929bE8Cd8382148C69053cE5ED1a9593EA7
        address private immutable _gateway;
        uint256 public number;
    
        constructor(address gateway) {
            _gateway = gateway;
        }
    
        function onGmpReceived(bytes32, uint128, bytes32, bytes calldata) external payable override returns (bytes32) {
            require(msg.sender == _gateway, "unauthorized");
            number++;
            return bytes32(number);
        }
    }
    

然后编译**IGateway.sol**这个文件

![](https://storage.googleapis.com/papyrus_images/b2c2a8e5e1a1c4deff748a4acfde646e2a845c5ca36d84b68b487852f7d6d0e1.png)

然后填入合约：**0xB5D83c2436Ad54046d57Cd48c00D619D702F3814** 部署合约

![](https://storage.googleapis.com/papyrus_images/faf35f476e92c477b29235898a97df4109b8321d2877761d3999c5dc6cba18d2.png)

钱包确认之后部署完成

复制我们的合约地址到区块链浏览器

[

Sepolia blockchain explorer - View Sepolia stats | Blockscout
-------------------------------------------------------------

Open-source block explorer by Blockscout. Search transactions, verify smart contracts, analyze addresses, and track network activity. Complete blockchain data and APIs for the Sepolia Explorer network.

https://eth-sepolia.blockscout.com

![](https://storage.googleapis.com/papyrus_images/935635827705cea2b23e09a23bb5cba5148677753b965d9d212798615ec9b83e.png)

](https://eth-sepolia.blockscout.com/)

![](https://storage.googleapis.com/papyrus_images/642b2e192b80ffda35729b98a21f84255ba0fd04070e9122595d11f24f4117fd.png)

搜索并进入我们部署的合约

点击Contract然后Verify & publish

![](https://storage.googleapis.com/papyrus_images/06ee01be7768ea5c555135f43f26567fc845a45eb81acb9bb074b2a26649543d.png)

然后按照截图选择和填写（最后填写的是**IGateway.sol**这个的代码）点击Verify & publish

![](https://storage.googleapis.com/papyrus_images/06a550845924be336bb0171540619ec06add4413360d93bc79a2d8b1113018ae.png)

最后前往：

[https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract](https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract)

按照截图填写信息，提交之后得到tx

![](https://storage.googleapis.com/papyrus_images/91beb438f19fdd709942d1bcbd4fa708c5671eb997baab01a7a16862db563d4d.png)

暂时积分任务就这些很简单的交互，本教程将持续更新

我是Rick，没有闲聊，没有广告，只是埋头苦干的黑奴，各位可以订阅关注更新，也可以关注我Twitter，每次任务更新后也会发帖：

---

*Originally published on [0xRick](https://paragraph.com/@0xb95/analog)*
