diff --git a/CHANGELOG.md b/CHANGELOG.md index da10ff37..769ae3e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Reference: + - Added the "Polygon ID State Replication" page; - Use Cases: - Added the "Identity State Replication" doc; - How-to-Guides: diff --git a/docs/reference/api.mdx b/docs/reference/api.mdx index 0efc318f..f5de0ed8 100644 --- a/docs/reference/api.mdx +++ b/docs/reference/api.mdx @@ -77,3 +77,4 @@ GitHub: https://github.com/rarimo/issuer | Mainnet | https://api.robotornot.rarimo.com | |----------|----------------------------| | Testnet | https://api.robotornot.mainnet-beta.rarimo.com | + diff --git a/docs/reference/polygonid-state-replication.mdx b/docs/reference/polygonid-state-replication.mdx new file mode 100644 index 00000000..813050bd --- /dev/null +++ b/docs/reference/polygonid-state-replication.mdx @@ -0,0 +1,234 @@ +--- +sidebar_label: Polygon ID State Replication +--- + +# Polygon ID State Replication + +This page contains technical resources related to the [Polygon ID State Replication](/use-cases/polygon-id). + +## Demo DApp + +Users can check out how the state replication works using our demo DApp. Leveraging the state replication lets users submit a Polygon ID zero-knowledge proof on Ethereum. Users get an SBT as a reward. + +Testnet(Sepolia): https://polygon.mainnet-beta.rarimo.com/ + +## Identity Relayer + +This service replicates GIST roots and identity states on demand. +Call it before submitting proof on the destination chain. + +- Github: https://github.com/rarimo/identity-relayer-svc +- API Reference: https://rarimo.github.io/rarimo-core/docs/common/bridging/002-identity.html +- Testnet URI: https://api.mainnet-beta.rarimo.com + +### Relayer endpoints + +To perform state publishing, you can execute POST `/integrations/relayer/state/relay` request with the following body: + +```json +{ + "chain": "Ethereum", + "hash": "0x212bc6f8194aa63eee97b0566b7cd65c66bb57cc4936c11e611f1042bb0b7118", + "waitConfirm": true +} +``` + +To perform GIST publishing, you can execute POST `/integrations/relayer/gist/relay` request with the following body: + +```json +{ + "chain": "Ethereum", + "hash": "0x1e4b74c14388fbfca27496828d24c248637792eb0286e7519860abb3ec01bc70", + "waitConfirm": true +} +``` + +- `"chain": "chain_name"` - chain, to which the state (or gist) will be relayed; +- `"hash": "0x..."` - hash of the state (or gist) to relay. Same as on the state contract in 0x... hex format; +- `"waitConfirm": true` indicates whether the request should wait until the transaction is included in the block (`false` by default); + +The response codes: +- `200` - successful relay, body contains tx hash; +- `404` - the state is not transferred yet; try to repeat the request later; +- `400` - state has been relayed before; + +## Smart Contracts + + + +### `LightweightStateV2` + +It's a modified state contract meant for the destination chains. +It checks a TSS from the Rarimo validators instead of a ZKP to transit the state and only holds a partial history. +The relayer service lazily updates the contract whenever a user wants to submit ZKP on a particular chain. + +#### Deployments + +|Chain| ChainID| Address| +| --- | --- | --- | +| Sepolia | `11155111` | `0x4EaEdFbD2156f5D77b11c4fE073032c4D90Dd315` \([Etherscan](https://sepolia.etherscan.io/address/0x4EaEdFbD2156f5D77b11c4fE073032c4D90Dd315)\) | + +#### Interface + +```solidity +contract LightweightStateV2 is ILightweightStateV2, UUPSSignableUpgradeable, Signers { + address public override sourceStateContract; + + uint256 internal _currentGistRoot; + + mapping(uint256 => GistRootData) internal _gistsRootData; + + mapping(uint256 => IdentityInfo) internal _identitiesInfo; + + function signedTransitGISTData( + uint256 prevGist_, + GistRootData calldata gistData_, + bytes calldata proof_ + ) external override { + // ... + + emit SignGISTDataTransited(gistData_.root, prevGist_); + } + + function signedTransitStateData( + uint256 prevState_, + StateData calldata stateData_, + bytes calldata proof_ + ) external override { + // ... + + emit SignStateDataTransited(stateData_.id, stateData_.state, prevState_); + } +} + +``` + +- `sourceStateContract` — address of the state contract on the source chain (Rarimo); +- `_currentGistRoot` — the latest transferred GIST root; +- `_gistsRootData` — mapping of the GIST roots to their data. +Data stores two roots, one that replaced the other, timestamp and block number; +- `_identitiesInfo` — mapping of the identity IDs to the information about this identity. +Information has the latest identity state and the history of the states with timestamps; +- `signedTransitGISTData()` — adds the GIST root to the history and changes the current root variable if the proposed one is newer; +- `signedTransitStateData(...)` — adds the state to the history and sets the last state of the identity to the provided one if it's newer; + +Both functions require proof of change — TSS of Rarimo signature providers. +Also, core functions emit events, which contain the data about changes: +- `SignGISTDataTransited` contains the data about roots, the previous one and the provided one; +- `SignStateDataTransited` contains the provided identity state, previous state, and identity ID; + +Full implementation can be found [here](https://github.com/rarimo/polygonid-integration-contracts/blob/master/contracts/LightweightStateV2.sol). + +### `QueryVerifier` + +It's an implementation of a verifier contract that inherits Iden3 [ZKPVerifier](https://github.com/iden3/contracts/blob/master/contracts/verifiers/ZKPVerifier.sol) that mints an SBT. +It is configured to work with the KYCAge demo credential. + +#### Deployments + +|Chain| ChainID| Address| +| --- | --- | --- | +| Sepolia | `11155111` | `0xb95734f64f242E976E155594E1E15D39700Cbb26` \([Etherscan](https://sepolia.etherscan.io/address/0xb95734f64f242E976E155594E1E15D39700Cbb26)\) | + +#### Interface + +```solidity +contract QueryVerifier is IQueryVerifier, ZKPVerifier { + uint256 public constant AGE_VERIFY_REQUEST_ID = 1; + + IVerifiedSBT public override sbtContract; + + mapping(address => uint256) public override addressToUserId; + + mapping(uint256 => VerificationInfo) internal _verificationsInfo; + + function _beforeProofSubmit( + uint64, + uint256[] memory inputs_, + ICircuitValidator + ) internal override { + require( + !isUserVerified(_getIdentityId(inputs_)), + "QueryVerifier: identity with this identifier has already been verified" + ); + require( + addressToUserId[msg.sender] == 0, + "QueryVerifier: current address has already been used to verify another identity" + ); + } + + function _afterProofSubmit( + uint64, + uint256[] memory inputs_, + ICircuitValidator + ) internal override { + uint256 tokenId_ = sbtContract.nextTokenId(); + uint256 userId_ = _getIdentityId(inputs_); + + _verificationsInfo[userId_] = VerificationInfo(msg.sender, tokenId_); + addressToUserId[msg.sender] = userId_; + + sbtContract.mint(msg.sender); + + emit Verified(userId_, msg.sender, tokenId_); + } +} +``` + +- `AGE_VERIFY_REQUEST_ID` — hard-coded KYC demo request ID; +- `sbtContract` — address of the SBT contract, which will be called to mint Soulbound token; +- `addressToUserId` — mapping of addresses to user's identity ID; +- `_verificationsInfo` — mapping of user's identity ID to the verification information, which contains the prover address and minted token ID; +- `_beforeProofSubmit` — hook that performs some necessary security checks; +- `_afterProofSubmit` — another hook, which mints the SBT in case of valid verification; + +The function that verifies the ZKP - `verify(...)` is inherited from the [ZKPVerifier](https://github.com/iden3/contracts/blob/master/contracts/verifiers/ZKPVerifier.sol) contract. + +Full implementation can be found [here](https://github.com/rarimo/polygonid-integration-contracts/blob/master/contracts/QueryVerifier.sol). + +### `VerifiedSBT` + +The SBT is awarded to users who complete the Polygon ID x Rarimo demo. + +#### Deployments + +|Chain| ChainID| Address| +| --- | --- | --- | +| Sepolia | `11155111` | `0x8A55c9CfDCbCeDcA1A543295a3F54351C335A20f` \([Etherscan](https://sepolia.etherscan.io/address/0x8A55c9CfDCbCeDcA1A543295a3F54351C335A20f)\) | + +#### Interface + +```solidity +contract VerifiedSBT is + IVerifiedSBT, + UUPSUpgradeable, + ERC721EnumerableUpgradeable, + OwnableUpgradeable +{ + address public override verifier; + uint256 public override nextTokenId; + string public override tokensURI; + + // ... + + function mint(address recipientAddr_) external override onlyVerifier {} + + function _beforeTokenTransfer( + address from_, + address to_, + uint256 firstTokenId_, + uint256 batchSize_ + ) internal override { + // ... + } +} +``` + +- `verifier` — address of the verifier's (`QueryVerifier`) contract; +- `nextTokenId` — nonce that is incremented each time a new SBT is created; +- `tokensURI` — token's picture URI; +- `onlyVerifier()` — modifier that allows calls only by the verifier contract; +- `mint(address)` — mints the SBT for the given address; +- `_beforeTokenTransfer(...)` — prevents the token from being transferred (only burn and mint are available); + +Full implementation can be found [here](https://github.com/rarimo/polygonid-integration-contracts/blob/master/contracts/VerifiedSBT.sol). diff --git a/sidebars.js b/sidebars.js index 7949c894..2a35e822 100644 --- a/sidebars.js +++ b/sidebars.js @@ -104,6 +104,10 @@ const sidebars = { type: "doc", id: "reference/proof-of-humanity", }, + { + type: "doc", + id: "reference/polygonid-state-replication", + }, { type: "doc", id: "reference/api",