
Web3 入圈(撸毛)红宝书/From Zero to Airdrop Hero: A Web3 Beginner’s Guide
我是0xRick,自2021年11月正式入圈开始截止到现在也有了差不多3个年头,从牛市末期一直到现在,从由现实中的A9朋友带我入圈到现在我自己做,从单打独斗到有社区朋友一起。 虽然在进入Web3之前,我也算拥有极强的计算机、互联网和金融经验(Web2一直从事的相关工作),但是进入Web3之后也学习了蛮长的时间才弄明白,在这个过程也非常感谢很多中文社群的分享和解答,也特别感谢我的朋友Jason。刚入圈就开始写投研报告和看其他社区写的在刚进入Web3,结合我的自身现实情况,Jason为我选定了0成本空投赛道(包括到现在我也是),有遇到很多坑,也有因为号少导致收益少了几百倍的情况。知道各位新人或者才从其他领域转至(主要是只做合约的)空投赛道的用户痛点,也是为了发扬一下分享精神,所以写了这篇教程。 如果各位是想了解撸毛/空投,或者是已经上手了,但是需要给自己现实中的朋友或者其他群的群友说这个概念而无从说起,可以把这个教程发给Ta看看,节省自己的时间和精力。 如果对你有帮助,请关注我的X,没有广告和闲聊,只有信息:关于空投在近两年,有一个议题经常在各种社交媒体上讨论,也经常有人在问我:空投...

Initia 保姆级激励测试网教程(更新Week2)
简介Initia是一个用于全链 Rollup 网络,通过将新颖的 L1 与特定于应用程序的 L2 基础设施系统融合而构建。Initia 平台提供产品就绪的 Rollup,使团队能够构建可扩展的主权系统,同时消除最终用户在与模块化多链宇宙交互时面临的用户体验复杂性。Initia 拥有完整的技术堆栈,可实现一套链级机制,使用户、开发者、L2 应用链和 L1 之间的经济利益保持一致。TwitterDiscordJoin the Initia Discord Server!The Initia Discord: A network for 0-to-1 conversations | 304804 membershttps://discord.com背景Initia 的两位核心开发人员Zon和Stan Liu曾就职于Terra的背后开发公司Terraform Labs,Zon是一名智能合约开发人员,而Liu正在研究 MEV。据The Block报道,两人离开Terraform Labs 并开始创建基于 Cosmos 的 DeFi 区块链。然而没过多久,就发生了 Terra/Luna 崩盘...

Movement激励测试网教程(更新54. Zeno Lend)
简介Movement 是一个模块化框架,用于在任何分布式环境中构建和部署基于 Move 的基础设施、应用程序和区块链。该团队正在构建一套产品和服务,使非 Move 协议能够利用 Move 编程语言的强大功能,而无需编写一行 Move 代码。该团队的第一个版本 M1 将 L1 重新定义为可垂直组合和水平可扩展的第 1 层框架,该框架与 Solidity 兼容,连接 EVM 和 Move 流动性,并允许构建者自定义具有不同用户基础和流动性的模块化和可互操作的应用程序链开箱即用。TwitterDiscordJoin the Movement Network Foundation Discord Server!Check out the Movement Network Foundation community on Discord - hang out with 101 other members and enjoy free voice and text chat.https://discord.com融资情况2023.9.13 Movement Labs 宣布完成 340 万美元的...



Web3 入圈(撸毛)红宝书/From Zero to Airdrop Hero: A Web3 Beginner’s Guide
我是0xRick,自2021年11月正式入圈开始截止到现在也有了差不多3个年头,从牛市末期一直到现在,从由现实中的A9朋友带我入圈到现在我自己做,从单打独斗到有社区朋友一起。 虽然在进入Web3之前,我也算拥有极强的计算机、互联网和金融经验(Web2一直从事的相关工作),但是进入Web3之后也学习了蛮长的时间才弄明白,在这个过程也非常感谢很多中文社群的分享和解答,也特别感谢我的朋友Jason。刚入圈就开始写投研报告和看其他社区写的在刚进入Web3,结合我的自身现实情况,Jason为我选定了0成本空投赛道(包括到现在我也是),有遇到很多坑,也有因为号少导致收益少了几百倍的情况。知道各位新人或者才从其他领域转至(主要是只做合约的)空投赛道的用户痛点,也是为了发扬一下分享精神,所以写了这篇教程。 如果各位是想了解撸毛/空投,或者是已经上手了,但是需要给自己现实中的朋友或者其他群的群友说这个概念而无从说起,可以把这个教程发给Ta看看,节省自己的时间和精力。 如果对你有帮助,请关注我的X,没有广告和闲聊,只有信息:关于空投在近两年,有一个议题经常在各种社交媒体上讨论,也经常有人在问我:空投...

Initia 保姆级激励测试网教程(更新Week2)
简介Initia是一个用于全链 Rollup 网络,通过将新颖的 L1 与特定于应用程序的 L2 基础设施系统融合而构建。Initia 平台提供产品就绪的 Rollup,使团队能够构建可扩展的主权系统,同时消除最终用户在与模块化多链宇宙交互时面临的用户体验复杂性。Initia 拥有完整的技术堆栈,可实现一套链级机制,使用户、开发者、L2 应用链和 L1 之间的经济利益保持一致。TwitterDiscordJoin the Initia Discord Server!The Initia Discord: A network for 0-to-1 conversations | 304804 membershttps://discord.com背景Initia 的两位核心开发人员Zon和Stan Liu曾就职于Terra的背后开发公司Terraform Labs,Zon是一名智能合约开发人员,而Liu正在研究 MEV。据The Block报道,两人离开Terraform Labs 并开始创建基于 Cosmos 的 DeFi 区块链。然而没过多久,就发生了 Terra/Luna 崩盘...

Movement激励测试网教程(更新54. Zeno Lend)
简介Movement 是一个模块化框架,用于在任何分布式环境中构建和部署基于 Move 的基础设施、应用程序和区块链。该团队正在构建一套产品和服务,使非 Move 协议能够利用 Move 编程语言的强大功能,而无需编写一行 Move 代码。该团队的第一个版本 M1 将 L1 重新定义为可垂直组合和水平可扩展的第 1 层框架,该框架与 Solidity 兼容,连接 EVM 和 Move 流动性,并允许构建者自定义具有不同用户基础和流动性的模块化和可互操作的应用程序链开箱即用。TwitterDiscordJoin the Movement Network Foundation Discord Server!Check out the Movement Network Foundation community on Discord - hang out with 101 other members and enjoy free voice and text chat.https://discord.com融资情况2023.9.13 Movement Labs 宣布完成 340 万美元的...
Share Dialog
Share Dialog

Subscribe to 0xRick

Subscribe to 0xRick
>100 subscribers
>100 subscribers
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 然后保存即可

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


或者前往(推荐此方法):
https://watch.testnet.analog.one/#/
链接钱包


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

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

前往
https://testnet.analog.one/#/?signup&referral=YJCC50
注册账号


绑定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地址:
钱包确认之后部署成功
复制合约地址

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

下拉页面,点击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);
}
}

然后前往
https://watch.testnet.analog.one/#/
点击顶部的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
前往
https://watch.testnet.analog.one/#/library
点击任意项目进入(上一步完成,也可以进入自己的项目)

点击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
前往
https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract
连接小狐狸钱包

然后拉开第三项填入如图数值
地址:
0xB5D83c2436Ad54046d57Cd48c00D619D702F3814

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


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

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

使用Gmail登录即可

Embark on the Analog Incentivized Odyssey!
前往
https://www.intract.io/quest/667405d2e1972009849c96dc?utm_source=dashboard
完成基础社交任务即可,都可以假过,需要MATIC Gas(7月30号结束)

TALISMAN
使用Talisman钱包(如果之前使用的其他钱包,可以将助记词导入然后再连接)
然后完成任务
任务页面拉至底部
分别进入两个Analog任务

点击之后,分别完成资助项目和转账的任务就可以Claim积分了
GMP Sepolia+shibuya测试网新代码
同样的,前往Remix:
和之前一样,创建.sol文件,不过这次需要创建3个
1.BranchlessMath.sol
2.Primitives.sol
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

最后前往:
https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract
按照截图填写信息,提交之后得到tx

暂时积分任务就这些很简单的交互,本教程将持续更新
我是Rick,没有闲聊,没有广告,只是埋头苦干的黑奴,各位可以订阅关注更新,也可以关注我Twitter,每次任务更新后也会发帖:
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 然后保存即可

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


或者前往(推荐此方法):
https://watch.testnet.analog.one/#/
链接钱包


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

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

前往
https://testnet.analog.one/#/?signup&referral=YJCC50
注册账号


绑定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地址:
钱包确认之后部署成功
复制合约地址

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

下拉页面,点击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);
}
}

然后前往
https://watch.testnet.analog.one/#/
点击顶部的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
前往
https://watch.testnet.analog.one/#/library
点击任意项目进入(上一步完成,也可以进入自己的项目)

点击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
前往
https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract
连接小狐狸钱包

然后拉开第三项填入如图数值
地址:
0xB5D83c2436Ad54046d57Cd48c00D619D702F3814

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


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

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

使用Gmail登录即可

Embark on the Analog Incentivized Odyssey!
前往
https://www.intract.io/quest/667405d2e1972009849c96dc?utm_source=dashboard
完成基础社交任务即可,都可以假过,需要MATIC Gas(7月30号结束)

TALISMAN
使用Talisman钱包(如果之前使用的其他钱包,可以将助记词导入然后再连接)
然后完成任务
任务页面拉至底部
分别进入两个Analog任务

点击之后,分别完成资助项目和转账的任务就可以Claim积分了
GMP Sepolia+shibuya测试网新代码
同样的,前往Remix:
和之前一样,创建.sol文件,不过这次需要创建3个
1.BranchlessMath.sol
2.Primitives.sol
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

最后前往:
https://sepolia.etherscan.io/address/0xB5D83c2436Ad54046d57Cd48c00D619D702F3814#writeContract
按照截图填写信息,提交之后得到tx

暂时积分任务就这些很简单的交互,本教程将持续更新
我是Rick,没有闲聊,没有广告,只是埋头苦干的黑奴,各位可以订阅关注更新,也可以关注我Twitter,每次任务更新后也会发帖:
// SPDX-License-Identifier: MIT
// Analog's Contracts (last updated v0.1.0) (src/utils/BranchlessMath.sol)
/**
*
@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));
}
}
// SPDX-License-Identifier: MIT
// Analog's Contracts (last updated v0.1.0) (src/Primitives.sol)
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)
}
}
}
// SPDX-License-Identifier: MIT
// Analog's Contracts (last updated v0.1.0) (src/utils/BranchlessMath.sol)
/**
*
@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));
}
}
// SPDX-License-Identifier: MIT
// Analog's Contracts (last updated v0.1.0) (src/Primitives.sol)
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)
}
}
}
No activity yet