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

简介

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

Twitter

Discord

融资情况

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%

原文地址:

交互准备

下载安装浏览器钱包

1.SubWallet(推荐)

2.Talisman

3.Polkadot.JS

4.Enkrypt

添加网络并领水

以SubWallet钱包为例(建议第二个方法添加)

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

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

或者前往(推荐此方法):

链接钱包

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

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

交互流程

前往

注册账号

绑定EVM钱包

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

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

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

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

任意挑选一个投票

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

Developer任务栏

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

下来页面,分别连接钱包(Sub和小狐狸)

Create an API Key

点击之后跳转页面

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

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

创建完成即可

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

部署一个智能合约

前往Remix

新建一个.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);
    }
}

然后编译合约

编译完成之后,部署合约

Sepolia的gateway地址:

0xB5D83c2436Ad54046d57Cd48c00D619D702F3814

钱包确认之后部署成功

复制合约地址

前往

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

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

跳转页面如截图选择,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);
    }
}

然后前往

点击顶部的Smart Contracts

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

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

然后填入Analog watch的下一步

勾选后点击List即上传成功

Build and deploy a View(7月更新)

点击个人主页,View Builder

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

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

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

Sponsor/Fund a Unique View

前往

点击任意项目进入(上一步完成,也可以进入自己的项目)

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

Query a Unique View

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

GMP

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

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

Send a message using a GMP gateway contract

前往

连接小狐狸钱包

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

地址:

0xB5D83c2436Ad54046d57Cd48c00D619D702F3814

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

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

DMAIL任务

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

使用Gmail登录即可

Embark on the Analog Incentivized Odyssey!

前往

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

TALISMAN

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

然后完成任务

任务页面拉至底部

分别进入两个Analog任务

点击之后,分别完成资助项目和转账的任务就可以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这个文件

然后填入合约:0xB5D83c2436Ad54046d57Cd48c00D619D702F3814 部署合约

钱包确认之后部署完成

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

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

点击Contract然后Verify & publish

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

最后前往:

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

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

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

Subscribe to 0xRick
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.