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