ONCHAINID源码分析(二)

news/2025/9/23 9:21:47/文章来源:https://www.cnblogs.com/lyhero11/p/19106576

ONCHAINID源码分析(二)

上一章节我们对ONCHAINID做了一个总览、对各个组成部分做了概要性质的讲解,然后着重对整套合约的部署框架和代理合约设计做了代码分析。这使得我们对整体有了一定的理解,本章我们继续学习ONCHAINID的业务逻辑部分。

业务逻辑主要集中在Verifier.solIdentity.solClaimIssuer.sol这三个文件里。

四、身份验证逻辑讲解

前文我们知道,通过部署框架我们得到了IdentityProxy的地址,以后调用这个代理合约就相当于调用Identity合约的逻辑,我们可以想象得到,在实际业务场景中一定是外部的系统或者合约需要在RWA业务逻辑中去使用我们的ONCHAINID去校验身份、也就是校验一个钱包地址对应的Identity合约(的IdentityProxy代理合约)是否具备必要的Claim,以及这些Claim是不是合规指定的Issuer签发的。这个逻辑就是写在Verifier.sol的,它是外部业务调用ONCHAINID的入口。另外这里也可以看出来身份Identity与身份验证Verifier解耦的设计思想,每个项目要求的用户身份可能会不同,我们可以针对一个特定的项目创建一个Verifier,而用户的身份合约则可以复用、不必每个项目都创建一次。

与之前一样,我摘选Verifier.sol相关的重要部分进行讲解,先看下几个状态变量:

uint256[] public requiredClaimTopics; //必须的Claims
IClaimIssuer[] public trustedIssuers; //指定的可信Issuers
mapping(address => uint256[]) public trustedIssuerClaimTopics; //可信Issuer与其可颁发的Claims的映射
mapping(uint256 => IClaimIssuer[]) public claimTopicsToTrustedIssuers;//所有可颁发某个Claim的Issuer

接下来我们看下主要方法verify(address identity)

function verify(address identity) public view returns(bool isVerified) {if (requiredClaimTopics.length == 0) {return true;}uint256 foundClaimTopic;uint256 scheme;address issuer;bytes memory sig;bytes memory data;uint256 claimTopic;//针对必须的ClaimTopic逐个进行判断:这个ClaimTopic叠加合约允许的签发者,得到ClaimIds,//然后去看Identity里有没有这个ClaimIds中的至少1个,有的话还要去Issuer那验证是否有效for (claimTopic = 0; claimTopic < requiredClaimTopics.length; claimTopic++) {IClaimIssuer[] memory trustedIssuersForClaimTopic =this.getTrustedIssuersForClaimTopic(requiredClaimTopics[claimTopic]);if (trustedIssuersForClaimTopic.length == 0) {return false;   //某个必须的claim对应的可信签发者一个都没有}//requiredClaimTopics[claimTopic]这个Claim允许哪些Issuer可以颁发,//为了理解更直观,假设有5个Issuer允许颁发、那么对应的Claim应该也是5个,那这5个Claim的ClaimId什么bytes32[] memory claimIds = new bytes32[](trustedIssuersForClaimTopic.length);for (uint256 i = 0; i < trustedIssuersForClaimTopic.length; i++) {claimIds[i] = keccak256(abi.encode(trustedIssuersForClaimTopic[i],                                                                                                                                                   requiredClaimTopics[claimTopic]));}//接下来看,入参的这个identity合约有没有这5个ClaimId中的至少1个for (uint256 j = 0; j < claimIds.length; j++) {(foundClaimTopic, scheme, issuer, sig, data, ) =IIdentity(identity).getClaim(claimIds[j]);if (foundClaimTopic == requiredClaimTopics[claimTopic]) { //这个Identity有该ClaimIdtry IClaimIssuer(issuer).isClaimValid(IIdentity(identity), requiredClaimTopics[claimTopic], sig,data) returns (bool _validity) {if (_validity) { //验证通过,结束循环,去判断下一个Claimj = claimIds.length;}if (!_validity && j == (claimIds.length - 1)) { //验证不通过,且5个都验证过了,falsereturn false;}} catch {if (j == (claimIds.length - 1)) {return false;}}} else if (j == (claimIds.length - 1)) { //这个Identity没有该ClaimId,且5个都没有,返回falsereturn false;}}}return true;
}

代码逻辑比价复杂,我们举例来帮助大家直观的理解:假设一个项目规定参与的用户必须取得topic为1、2的Claim,并且规定只认可A B C D E这5个Issuer颁发的这些Claim。那么我们就要去Identity里看看ClaimId(A,1), ClaimId(B,1) ... ClaimId(E,1)至少要有1个、且对应的Claim到其颁发者处可以验证通过,同理ClaimId(A,2), ClaimId(B,2) ... ClaimId(E,2)也是至少要有1个且可验证有效。这就是verify(address identity)方法的主要逻辑。

五、用户身份合约Identity的管理

回顾前面IdFactory创建IdentityProxy,我们可以看到是将用户的钱包地址与IdentityProxy合约进行了关联的,且作为了管理Key:

//IdentityProxy的构造方法
//nitialManagementKey就是IdFactory用create2调用创建IdentityProxy时候传入的钱包地址
constructor(address _implementationAuthority, address initialManagementKey) {//通过delegatecall调用实现合约Identity的initialize(address)方法逻辑,完成对代理合约的创建
} 

这似乎意味着用户可以自己管理自己的身份合约。实际上确实是这样,作为Web3.0的数字身份系统,用户必然是有权利管理自己的身份的(也只有用户自己有最高权限,平台创建完IdentityProxy之后没有保留控制权、不能直接操作用户这个身份合约)。我们来分析一下“原型”Identity合约、因为用户身份管理业务逻辑都是在这里边的,这也是ONCHAINID这套合约的核心部分之一、也比较复杂。照例我选取主要的代码进行讲解:

先看看对于这个合约而言很重要的modifier部分:

//只能通过代理合约 fallback() delegatecall调用,逻辑合约里_canInteract == false
modifier delegatedOnly() {require(_canInteract == true, "Interacting with the library contract is forbidden.");_;
}//合约的MANAGEMENT key才能调用,代理合约创建的时候传入的那个用户钱包地址就是MANAGEMENT
//msg.sender == address(this)内部调用也可以
modifier onlyManager() {require(msg.sender == address(this) || keyHasPurpose(keccak256(abi.encode(msg.sender)), 1), "Permissions: Sender does not have management key");_;
}//合约CLAIM key才能调用,  Issuer持有
modifier onlyClaimKey() {require(msg.sender == address(this) || keyHasPurpose(keccak256(abi.encode(msg.sender)), 3), "Permissions: Sender does not have claim signer key");_;
}

可以看到对于Identity合约的方法可以通过delegatedOnly指定只能通过代理合约进行调用、onlyManager来指定方法只有这个身份管理员才可以调用(一般是用户钱包地址)、通过onlyClaimKey指定该方法只有Issuer可以调用(谁是本身份合约的Issuer Key也是需要用户MANAGEMENT key指定)。

我们接下来对用于管理身份的几个重点方法进行讲解:

function addKey(bytes32 _key, uint256 _purpose, uint256 _type)publicdelegatedOnlyonlyManageroverridereturns (bool success)function removeKey(bytes32 _key, uint256 _purpose)publicdelegatedOnlyonlyManageroverridereturns (bool success)function addClaim(uint256 _topic,uint256 _scheme,address _issuer,bytes memory _signature,bytes memory _data,string memory _uri)publicdelegatedOnlyonlyClaimKeyoverridereturns (bytes32 claimRequestId)function removeClaim(bytes32 _claimId)publicdelegatedOnlyonlyClaimKeyoverridereturns(bool success) 

关于Key管理的两个方法addKeyremoveKey,可以看到都是需要有管理权限的地址(一般就是钱包地址)通过代理合约才能调用的。这两个方法是为这个身份合约添加或移除具有不同功能权限(Purpose)的地址。MANAGEMENT、ACTION是身份合约对应的主体内部来分权限来做分工; CLAIM意味着这个地址可以给本合约添加和移除Claim;addClaimremoveClaim一般是由身份颁发机构来调用,用户钱包地址作为管理员将Issuer的地址addKey添加为3 CLAIM,然后Issuer就可以为本合约添加和移除Claim了。

注,key Purpose 分以下4种:

  • 1: MANAGEMENT keys, which can manage the identity 管理Identity的key

  • 2: ACTION keys, which perform actions in this identity name

(signing, logins, transactions, etc.) 具体行为 签名、登录、交易

  • 3: CLAIM signer keys, used to sign claims on other identities

which need to be revokable. 给其他identity签发claims

  • 4: ENCRYPTION keys, used to encrypt data e.g. hold in claims.用来给claim里的data加密

Identity合约里还有两个重要的方法executeapprove,它们是身份合约与外部业务合约交互的接口,比如说与RWA合约。

先来看看execute方法:

function execute(address _to,      //要交互的合约地址uint256 _value,     //发送ETH金额bytes memory _data)  //函数选择器+入参ABIexternaldelegatedOnlyoverridepayablereturns (uint256 executionId)
{uint256 _executionId = _executionNonce; //在Storage.sol里定义_executions[_executionId].to = _to;     //插入待执行队列_executions[_executionId].value = _value;_executions[_executionId].data = _data;_executionNonce++;emit ExecutionRequested(_executionId, _to, _value, _data);//是身份合约管理员发起的调用,直接许可执行if (keyHasPurpose(keccak256(abi.encode(msg.sender)), 1)) {approve(_executionId, true);}//调用者具有ACTION权限,并且_to不是本合约,直接许可执行else if (_to != address(this) && keyHasPurpose(keccak256(abi.encode(msg.sender)), 2)){approve(_executionId, true);}//其他情况,等待approve方法进行许可执行return _executionId;
}

execute入参里的_data这里说明一下,这是目标函数选择器+入参的ABI编码,比如我们要调用的函数是RWA合约的subscribe(uint256 amount)方法,那么会有如下的过程使用execute进行执行:

// 1. 用abi.encodeWithSelector组装_data
bytes memory _data = abi.encodeWithSelector(IRWA.subscribe.selector,  // 目标函数选择器amount                    // 参数);// 2. 调用IdentityProxy.execute
identity.execute(rwaAddress,0,      // msg.value,如果需要ETH就写金额_data    // 组装好的调用数据);

调用者调用当前身份合约的execute方法去与指定合约_to去做交互。如果是调用者是管理员MANAGEMENT权限,则直接许可,如果是ACTION权限且交互的是其他合约则许可,其他情况需要等待通过approve另行许可。

简单来说,如果_to是本合约,那么说明是要对当前身份合约做管理动作,需要是管理员,可以直接执行。

如果_to是其他合约,那么说明是以当前身份合约之名对外做具体行为,比如签名、登录、交易,那么具有ACTION权限或者管理员都可以直接执行。

其他情况,比如非管理员执行本合约管理,那么进入待许可执行队列、等待approve; 再比如与外合约交互、调用者又没有ACTION权限,也同样进入待许可执行队列、等待approve;

再来看看approve方法:

function approve(uint256 _id, bool _approve)publicdelegatedOnlyoverridereturns (bool success){require(_id < _executionNonce, "Cannot approve a non-existing execution");require(!_executions[_id].executed, "Request already executed");//如果调用对象是本合约,需要是MANAGEMENT来许可(或拒绝)if(_executions[_id].to == address(this)) {require(keyHasPurpose(keccak256(abi.encode(msg.sender)), 1), "Sender does not have management key");}else { //如果是与外合约交互,需要ACTION来许可(或拒绝)require(keyHasPurpose(keccak256(abi.encode(msg.sender)), 2), "Sender does not have action key");}emit Approved(_id, _approve);if (_approve == true) { //许可_executions[_id].approved = true;// solhint-disable-next-line avoid-low-level-calls(success,) = _executions[_id].to.call{value:(_executions[_id].value)}(_executions[_id].data);if (success) { //如果执行成功_executions[_id].executed = true;emit Executed(_id,_executions[_id].to,_executions[_id].value,_executions[_id].data);return true;} else { //执行失败emit ExecutionFailed(_id,_executions[_id].to,_executions[_id].value,_executions[_id].data);return false;}} else { //拒绝_executions[_id].approved = false;}return false;
}

approve方法里在对当前许可调用者的权限做了判断之后,做了主要操作(success,) = _executions[_id].to.call{value:(_executions[_id].value)}(_executions[_id].data)_executions[_id].to是需要交互的合约地址,call方法是在当前身份合约的approve方法里发起的,所以相当于是本身份合约调用了这个需要交互合约,转_executions[_id].value这么多的ETH,然后执行的方法和入参是_executions[_id].data

好了,最后我们结合RWA的场景,总结一下身份合约的管理,以及通过execute方法作为接口、如何以身份合约去与外部合约进行交互:

  1. 基础身份结构
  • IdentityProxy 合约:代表投资者公司(法人身份)。

  • Key 管理

    • MANAGEMENT Key → 类似董事会/法人代表的权力,能增删 key,决定身份合约本身的治理。

    • ACTION Key → 类似公司财务、投资经理的权力,可以对外部协议执行交易。

    • CLAIM Key → 给发行方(Issuer)添加/移除合规声明用。


  1. execute/approve 的逻辑
  • execute → 发起一笔执行请求。可能是投资操作(比如买入代币、参与流动性池、质押资产)。

  • approve → 对这笔请求进行许可(Approve=true 或 Revoke=false),然后实际执行交易。

关键点:

  • 如果调用者是 MANAGEMENT Key → 可以直接 approve 并执行,无需额外许可。

  • 如果调用者是 ACTION Key 且目标是外部合约 → 也能直接 approve 并执行。

  • 如果目标是 本合约(IdentityProxy 自己) → 必须要 MANAGEMENT Key 来 approve。


  1. RWA 场景下的业务使用

假设 身份合约代表某公司去投资 RWA 协议(如链上基金、债券代币、地产 SPV 代币等)

例子 A:公司财务(ACTION Key)操作

  • 财务或投资经理通过 execute 调用 RWA 协议的 subscribe() 方法,投入 USDC 购买债券代币。

  • 因为 _to 是外部合约(RWA 协议),只要财务持有 ACTION Key,execute 会自动触发 approve(..., true) 并立即执行 → 资金立刻划出。 👉 所以,财务可以直接完成投资操作,不需要多签确认。

例子 B:公司内部治理调整

  • 假设需要修改 IdentityProxy 的 key(比如撤销某财务的 ACTION Key,或者增加一个新的董事 KEY)。

  • 这种情况属于对合约自身的调用(_to == address(this))。

  • 只能由 MANAGEMENT Key 来 approve 并最终执行。 👉 财务不能修改权限,必须董事会/法人代表来操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/912031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gl账号注册网站沧州网站优化价格

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

福田网站建设流程网站设计网页配色

std::future —C17 多线程 std::future C标准程序库使用future来模拟这类一次性事件&#xff1a;若线程需等待某个特定的一次性事件发生&#xff0c;则会以恰当的方式取得一个future&#xff0c;它代表目标事件&#xff1b;接着&#xff0c;该线程就能一边执行其他任务&#…

云服务器搭建网站教程苏州做外贸网站

【README】 本文转自bilibili《计算机组成原理&#xff08;哈工大刘宏伟&#xff09;》的视频讲解&#xff0c;非常棒&#xff0c;墙裂推荐&#xff1b; 【1】中断介绍 1&#xff09;作用&#xff1a;用中断系统实现了外设数据的输入输出&#xff1b; 还可以用于程序调试&…

东庄水利枢纽建设公司网站本地网站建设教程xampp

《精通Unix下C语言编程与项目实践》读书笔记(new)文章试读 不拘一个遍程序系列&#xff1a;编程序不能一个脑袋钻到底&#xff0c;有时要学会变通&#xff0c;即所谓的曲线救国。一、二、三、四职场规划&#xff1a;一些杂七杂八的职场感悟吧。不值钱的软件人才 精力充沛与事业…

展览馆网站建设西安做网站朋朋网络

工作中&#xff0c;经常遇到端口转发的情况。实现的方式很多种&#xff0c;个人感觉还是用nginx实现方便一些。我的环境是ubuntu 22.04, 路由器开通端口段全部映射到这台机器&#xff0c;然后再由它转发给各兄弟机。 /etc/nginx/nginx.conf, 文末位置加入&#xff1a; stream…

烟台招远网站建设牛杂网这类网站怎么做的

分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09; 目录 分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1.M…

集客营销软件官方网站微营销

先上原链接&#xff0c;一个很不错的wpf图标库 : https://github.com/MahApps/MahApps.Metro.IconPacks提供了大量的图标可以用&#xff0c;如下图&#xff1a;&#xff08;部分截图&#xff09;简单分析了一下代码&#xff0c;并模仿它写一个图标类和简单的使用示例&#xff1…

织梦导航网站模板武安信息港

高盛&#xff0c;作为全球领先的金融机构之一&#xff0c;近日发布了一份报告&#xff0c;预测在科技巨头的涨势推动下&#xff0c;标普500指数年底前有望升至6000点。这一预测引起了市场的广泛关注&#xff0c;投资者们纷纷开始重新评估自己的投资策略。 David Kostin等策略师…

做淘宝店铺有哪些好的网站建设公众号官方网站

PyCryptodome是python一个强大的加密算法库&#xff0c;可以实现常见的单向加密、对称加密、非对称加密、非对称加密算法签名和流加密算法。 直接pip安装即可&#xff1a;pip install pycryptodome 官网地址&#xff1a;https://pypi.org/project/pycryptodome/ 一、base64编码…

最佳三维文件格式,以及怎么在线浏览编辑FBX/OBJ/GLB/GLTF

什么是专有 3D 文件格式专有 3D 文件类型是特定于特定软件或公司的格式。专有文件格式的示例包括.max (3ds Max)、.blend (Blender)、.c4d (Cinema 4D)。 这些 3D 文件格式通常因其专有软件的功能丰富的选项而受…

秸秆可以发酵吗网站建设吗莱芜杂谈话题

个人主页 水月梦镜花 个人专栏 C语言 &#xff0c;数据结构 文章目录 一、顺序表二、实现思路1.存储结构2.初始化顺序表(SeqListInit)3.销毁顺序表(SeqListDestroty)4.打印顺序表(SeqListPrint)5.顺序表尾插(SeqListPushBack)and检查容量(SeqListCheckCapacity)6.顺序表头插(Se…

欧美平面设计网站网站后台账户如何做会计分录

前言 由于需要使用不同的qt环境&#xff08;PySide&#xff0c;PyQt&#xff09;所以写了这个脚本&#xff0c;使用找到的随便一个rcc命令去转换qrc文件&#xff0c;然后将导入模块换成qtpy这个通用库(支持pyside2-6&#xff0c;pyqt5-6)&#xff0c;老版本的是Qt.py(支持pysi…

网站建设属开票核定税种网络设计实践课程报告

在游戏开发领域&#xff0c;虚拟世界游戏定制开发是一项引人注目的任务&#xff0c;旨在满足客户独特的需求和愿景&#xff0c;创造一个完全个性化的虚拟世界游戏。这种类型的游戏开发需要专业的技能、深刻的游戏开发知识和密切的与客户合作&#xff0c;以确保游戏满足客户的期…

站长之家音效南京较好的网站制作公司

下面的讨论是我对《对编程实现拟人智能可行性的论证》这篇文章的“赋值与对象的标志”这一节的展开讨论。 标志能够使我们更好的思维&#xff08;比如用轮廓标记物体对象&#xff0c;用兴奋强度标记回忆情况等等&#xff09;。有思维标志、信息标志&#xff0c;单纯标志、组合…

温泉酒店网站建设方案英文网站优化

今天发现一个很有意思的问题&#xff0c;正常解决项目中产生的循环依赖&#xff0c;是找出今天添加的注入代码&#xff0c;然后一个个加lazy试过去&#xff0c;会涉及到类中新增的注入 但是今天修改了某个serviceimpl的方法&#xff0c;加入了Async方法后 就发生循环依赖了 ai…

河北网站建设推广自己做的网站怎么发布视频教程

一、说明 本系列是关于学习如何使用 ROS2、Docker 和 Github 设计、设置和维护机器人项目。 先决条件 — ROS2 软件包的基本知识、实现发布者、订阅者、操作并连接它们。 我们之前在 ROS2 中了解了不同的部分。但是&#xff0c;在我们转向实际的基于硬件的项目之前&#xff0c;…

ChatGPT 在招聘诈骗领域的应用

ChatGPT 在招聘诈骗领域的应用作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客 zhihu Github 公众号:一本正经的瞎扯事件经过 整个八月我都没有上班,在等待新的工作签证审批通过。 工作签证有…

FR报表下拉框高度(JS添加css样式方式)调整

FR报表下拉框高度调整解决方案 问题描述 在FR报表开发中,点击下拉框按钮后,下拉选项列表的高度太小,用户体验不佳。直接使用 $(.fr-combo-list).css("height","400px") 设置高度往往不生效,因…

基于Python+Vue开发的新闻管理系统源码+运行步骤

项目简介该项目是基于Python+Vue开发的新闻管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Pyt…

鸿蒙应用开发从入门到实战(十二):ArkUI组件ButtonToggle

ArkUI提供了丰富的系统组件,用于制作鸿蒙原生应用APP的UI,本文主要讲解按钮组件Button和Toggle的使用。大家好,我是潘Sir,持续分享IT技术,帮你少走弯路。《鸿蒙应用开发从入门到项目实战》系列文章持续更新中,陆…