欢迎光临
我们一直在努力

ONCHAINID数字身份合约源码导读

本文阅读需要有一点Solidity的基础,但不需要是高手,跟着本文讲解去看就可以看懂和理解。

RWA不同于DiFi、 Dex那种资产交易都整个的在链上全闭环的生态,现实资产通证化,参与的人当然也需要做现实世界的认证,不能是全匿名的。比如说做实名认证、合格投资者认证、反洗钱等等。是需要链下认证跟链上身份进行结合的。所以需要把链下身份跟链上的钱包地址能关联起来,这样跟RWA合约交互的时候就可以满足合规要求。

一、概要

ONCHAINID是一套链上数字身份的Solidity智能合约框架,面向合规应用场景,由 Tokeny 开发,用来把“链下身份(护照、KYC认证等等)”和“链上地址”关联起来。可以通过将Identity合约关联到链上钱包地址、并让权威Issuer颁发Claim给到Identity合约的方式,实现对链上身份的认证,用于KYC\\AML等场景。在RWA广泛应用的ERC-3643的T-REX实现,就是使用的ONCHAINID来做身份验证的。

二、目录结构

ONCHAINID这套合约的目录和合约源代码文件如下:

.
├── ClaimIssuer.sol
├── Identity.sol
├── Test.sol
├── _testContracts
│   └── VerifierUser.sol
├── factory
│   ├── IIdFactory.sol
│   └── IdFactory.sol
├── gateway
│   └── Gateway.sol
├── interface
│   ├── IClaimIssuer.sol
│   ├── IERC734.sol
│   ├── IERC735.sol
│   ├── IIdentity.sol
│   └── IImplementationAuthority.sol
├── proxy
│   ├── IdentityProxy.sol
│   └── ImplementationAuthority.sol
├── storage
│   ├── Storage.sol
│   └── Structs.sol
├── verifiers
│   └── Verifier.sol
└── version
└── Version.sol

我们先总揽一下,这套合约主要分以下这么几个部分:

IERC734.sol ,IERC735.sol是基础协议接口,定义oid合约具有“Key Holder”和“Claim Holder”的功能。Claim Holder比较好理解,身份合约肯定需要一些身份认证标签,这就需要认证机构颁发Claim给到这个oid合约;oid合约有时候不仅仅是关联到一个钱包地址就完了,还需要设置一些角色权限,比如这个钱包地址代表的是一个公司或者项目,那么就需要分权限来多个钱包一起管理,Key Holder是在oid合约里定义并存放这些公钥Key的功能。

IIdentity.sol, Identity.sol是oid的主体部分,一般说oid合约就是指的这个合约。

Storage.sol, Structs.sol是Identity合约的存储,业务逻辑与状态变量的存储分离是设计可升级可约的常用技巧,可以在存储合约预留的gap变量存储里直接追加而不会打乱合约的StorageLayout,实现合约字段扩充。而字段扩充和合约逻辑的改写,实际上是重新生成了一个新合约,地址会变的,这时候就用到代理合约模式,后面会提到。

IClaimIssuer.sol, ClaimIssuer.sol是特殊的Identity,指的是颁发认证的机构。这个合约内部存储撤销的Claim,以及实现了撤销方法、还有验证Claim是否可信的方法。

Verifier.sol代表一组规则逻辑,里边定义了合规必须的Claim以及对应的可信Claim,然后用verify(address identity)去校验Identity是否满足身份验证的标准。属于是一个业务规则逻辑模块。比如“合格投资者”,那这个肯定是要对应这个投资者Identity需要取得哪些issuer颁发的哪些claim,那么给定的Identity,我们需要判断每个requiredClaimTopics这个Identity是否都有、然后这个claim topic是不是规定的issuer发的。这个校验逻辑对应的主要方法就是verify(address identity)。

ImplementationAuthority.sol,IImplementationAuthority.sol,IdentityProxy.sol这些就是上面提到过的代理合约模式的实现,ImplementationAuthority就是个存放业务逻辑实现合约Identity的地址的容器,IdentityProxy.sol是代理合约,构造函数初始化的时候会传入ImplementationAuthority从而可以获得实现合约,通过调用代理合约来路由到实现合约对应的方法。这里用的是fallback()模式,调用代理合约时、方法名字用的是实现合约的方法,但代理合约里没有实现这些方法,所以统一会走到fallback()方法里,在fallback()方法里用assembly做delegatecall路由调用对应实现合约的方法逻辑。

Gateway.sol、IdFactory.sol、IIdFactory.sol是整套合约的部署框架,Gateway是外部部署调用的入口,网关通过调用IdFactory的方法实现对整套合约的部署调用和集成。

接下来,我准备从部署时候的初始化开始,从整体到细节带大家熟悉一下这套合约。

三、部署初始化逻辑讲解

我们先看下Gateway.sol里边的代码,我把我讲解需要的相关的代码列一下:

//谁可以调用Gateway来进行部署
mapping(address => bool) public approvedSigners;
//Gateway创建的时候,指定关联的IdFactory,以及指定有权限部署的地址名单
constructor(address idFactoryAddress, address[] memory signersToApprove) Ownable() {…}

//为identityOwner创建一个IdentityProxy合约
function deployIdentityWithSalt(
address identityOwner, //Identity是给谁的
string memory salt, //自定义盐,用于Create2
uint256 signatureExpiry, //签名失效时间
bytes calldata signature //部署所需的签名,必须是approvedSigners
) external returns (address) {
if (identityOwner == address(0)) {
revert ZeroAddress();
}

if (signatureExpiry != 0 && signatureExpiry < block.timestamp) {
revert ExpiredSignature(signature);
}
//用签名和签名内容hash、来恢复signer
address signer = ECDSA.recover(
keccak256(
abi.encode(
\”Authorize ONCHAINID deployment\”,
identityOwner,
salt,
signatureExpiry
)
).toEthSignedMessageHash(),
signature
);

if (!approvedSigners[signer]) { //signer是否被许可
revert UnapprovedSigner(signer);
}

if (revokedSignatures[signature]) { // 到撤销签名数组里检查一下签名是不是已撤销的
revert RevokedSignature(signature);
}

return idFactory.createIdentity(identityOwner, salt); //调用工厂合约进行部署
}

可以看到,主要是维护部署管理员白名单,然后调用IdFactory进行部署、为制定的identityOwner创建IdentityProxy合约。

我们接着看IdFactory里的逻辑。

constructor (address implementationAuthority) {
require(implementationAuthority != address(0), \”invalid argument – zero address\”);
_implementationAuthority = implementationAuthority;
}

function createIdentity(address _wallet, string memory _salt) external onlyOwner override returns (address) {
require(_wallet != address(0), \”invalid argument – zero address\”);
require(keccak256(abi.encode(_salt)) != keccak256(abi.encode(\”\”)), \”invalid argument – empty string\”);
string memory oidSalt = string.concat(\”OID\”,_salt);
require (!_saltTaken[oidSalt], \”salt already taken\”); //salt已经用过了,身份合约不能重复创建
require (_userIdentity[_wallet] == address(0), \”wallet already linked to an identity\”); //钱包地址已经关联过IdentityProxy合约了
ad

赞(0)
未经允许不得转载:171主机测评 » ONCHAINID数字身份合约源码导读
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址