mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
make contract sdk simpler (#514)
* make contract sdk simpler * reduce root inputs * delete convert function * summarize our library * update npm package * update package version * update attestation id * add util function to get revealed data
This commit is contained in:
@@ -22,9 +22,9 @@ CIRCUITS=(
|
||||
"dsc_sha512_ecdsa_brainpoolP512r1:21:false"
|
||||
|
||||
# RSA circuits
|
||||
"dsc_sha1_rsa_65537_4096:21:true"
|
||||
"dsc_sha1_rsa_65537_4096:21:false"
|
||||
"dsc_sha256_rsa_65537_4096:21:true"
|
||||
"dsc_sha512_rsa_65537_4096:21:true"
|
||||
"dsc_sha512_rsa_65537_4096:21:false"
|
||||
|
||||
# RSA-PSS circuits
|
||||
"dsc_sha256_rsapss_3_32_3072:22:false"
|
||||
|
||||
7380
circuits/yarn.lock
7380
circuits/yarn.lock
File diff suppressed because it is too large
Load Diff
5857
common/yarn.lock
5857
common/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import {IVcAndDiscloseCircuitVerifier} from "../interfaces/IVcAndDiscloseCircuit
|
||||
import {IIdentityVerificationHubV1} from "../interfaces/IIdentityVerificationHubV1.sol";
|
||||
import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol";
|
||||
import {CircuitConstants} from "../constants/CircuitConstants.sol";
|
||||
import {AttestationId} from "../constants/AttestationId.sol";
|
||||
|
||||
/**
|
||||
* @title SelfVerificationRoot
|
||||
@@ -22,8 +23,8 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
uint256 internal _scope;
|
||||
|
||||
/// @notice The attestation ID that proofs must match
|
||||
/// @dev Used to validate that submitted proofs contain the correct attestation
|
||||
uint256 internal _attestationId;
|
||||
/// @dev Used to validate that submitted proofs is generated with allowed attestation IDs
|
||||
mapping(uint256 => bool) internal _attestationIds;
|
||||
|
||||
/// @notice Configuration settings for the verification process
|
||||
/// @dev Contains settings for age verification, country restrictions, and OFAC checks
|
||||
@@ -33,6 +34,29 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
/// @dev Immutable reference used for proof verification
|
||||
IIdentityVerificationHubV1 internal immutable _identityVerificationHub;
|
||||
|
||||
// ====================================================
|
||||
// Circuit Constants
|
||||
// ====================================================
|
||||
|
||||
// Make CircuitConstants available to inheriting contracts
|
||||
uint256 internal constant REVEALED_DATA_PACKED_INDEX = CircuitConstants.VC_AND_DISCLOSE_REVEALED_DATA_PACKED_INDEX;
|
||||
uint256 internal constant FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX = CircuitConstants.VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX;
|
||||
uint256 internal constant NULLIFIER_INDEX = CircuitConstants.VC_AND_DISCLOSE_NULLIFIER_INDEX;
|
||||
uint256 internal constant ATTESTATION_ID_INDEX = CircuitConstants.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX;
|
||||
uint256 internal constant MERKLE_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_MERKLE_ROOT_INDEX;
|
||||
uint256 internal constant CURRENT_DATE_INDEX = CircuitConstants.VC_AND_DISCLOSE_CURRENT_DATE_INDEX;
|
||||
uint256 internal constant PASSPORT_NO_SMT_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX;
|
||||
uint256 internal constant NAME_DOB_SMT_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX;
|
||||
uint256 internal constant NAME_YOB_SMT_ROOT_INDEX = CircuitConstants.VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX;
|
||||
uint256 internal constant SCOPE_INDEX = CircuitConstants.VC_AND_DISCLOSE_SCOPE_INDEX;
|
||||
uint256 internal constant USER_IDENTIFIER_INDEX = CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX;
|
||||
|
||||
// ====================================================
|
||||
// Attestation ID
|
||||
// ====================================================
|
||||
|
||||
bytes32 constant E_PASSPORT_ID = AttestationId.E_PASSPORT;
|
||||
|
||||
// ====================================================
|
||||
// Errors
|
||||
// ====================================================
|
||||
@@ -49,31 +73,78 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
* @notice Initializes the SelfVerificationRoot contract.
|
||||
* @param identityVerificationHub The address of the Identity Verification Hub.
|
||||
* @param scope The expected proof scope for user registration.
|
||||
* @param attestationId The expected attestation identifier required in proofs.
|
||||
* @param olderThanEnabled Flag indicating if 'olderThan' verification is enabled.
|
||||
* @param olderThan Value for 'olderThan' verification.
|
||||
* @param forbiddenCountriesEnabled Flag indicating if forbidden countries verification is enabled.
|
||||
* @param forbiddenCountriesListPacked Packed list of forbidden countries.
|
||||
* @param ofacEnabled Array of flags indicating which OFAC checks are enabled. [passportNo, nameAndDob, nameAndYob]
|
||||
* @param attestationIds The expected attestation identifiers required in proofs.
|
||||
*/
|
||||
constructor(
|
||||
address identityVerificationHub,
|
||||
uint256 scope,
|
||||
uint256 attestationId,
|
||||
bool olderThanEnabled,
|
||||
uint256 olderThan,
|
||||
bool forbiddenCountriesEnabled,
|
||||
uint256[4] memory forbiddenCountriesListPacked,
|
||||
bool[3] memory ofacEnabled
|
||||
uint256[] memory attestationIds
|
||||
) {
|
||||
_identityVerificationHub = IIdentityVerificationHubV1(identityVerificationHub);
|
||||
_scope = scope;
|
||||
_attestationId = attestationId;
|
||||
_verificationConfig.olderThanEnabled = olderThanEnabled;
|
||||
_verificationConfig.olderThan = olderThan;
|
||||
_verificationConfig.forbiddenCountriesEnabled = forbiddenCountriesEnabled;
|
||||
_verificationConfig.forbiddenCountriesListPacked = forbiddenCountriesListPacked;
|
||||
_verificationConfig.ofacEnabled = ofacEnabled;
|
||||
for (uint256 i = 0; i < attestationIds.length; i++) {
|
||||
_attestationIds[attestationIds[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Updates the verification configuration
|
||||
* @dev Used to set or update verification parameters after contract deployment
|
||||
* @param verificationConfig The new verification configuration to apply
|
||||
*/
|
||||
function _setVerificationConfig(
|
||||
ISelfVerificationRoot.VerificationConfig memory verificationConfig
|
||||
) internal {
|
||||
_verificationConfig = verificationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the current verification configuration
|
||||
* @dev Used to retrieve the current verification settings
|
||||
* @return Current verification configuration
|
||||
*/
|
||||
function _getVerificationConfig() internal view returns (ISelfVerificationRoot.VerificationConfig memory) {
|
||||
return _verificationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Updates the scope value
|
||||
* @dev Used to change the expected scope for proofs
|
||||
* @param newScope The new scope value to set
|
||||
*/
|
||||
function _setScope(uint256 newScope) internal {
|
||||
_scope = newScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Adds a new attestation ID to the allowed list
|
||||
* @dev Used to add support for additional attestation types
|
||||
* @param attestationId The attestation ID to add
|
||||
*/
|
||||
function _addAttestationId(uint256 attestationId) internal {
|
||||
_attestationIds[attestationId] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Removes an attestation ID from the allowed list
|
||||
* @dev Used to revoke support for specific attestation types
|
||||
* @param attestationId The attestation ID to remove
|
||||
*/
|
||||
function _removeAttestationId(uint256 attestationId) internal {
|
||||
_attestationIds[attestationId] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Helper function to get an array of revealed data values from proof signals
|
||||
* @dev Returns an array of the three packed revealed data values
|
||||
* @param pubSignals The proof's public signals
|
||||
* @return revealedDataPacked Array of the three packed revealed data values
|
||||
*/
|
||||
function getRevealedDataPacked(uint256[21] memory pubSignals) internal pure returns (uint256[3] memory revealedDataPacked) {
|
||||
revealedDataPacked[0] = pubSignals[REVEALED_DATA_PACKED_INDEX];
|
||||
revealedDataPacked[1] = pubSignals[REVEALED_DATA_PACKED_INDEX + 1];
|
||||
revealedDataPacked[2] = pubSignals[REVEALED_DATA_PACKED_INDEX + 2];
|
||||
return revealedDataPacked;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +153,7 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
* @param proof The proof data for verification and disclosure
|
||||
*/
|
||||
function verifySelfProof(
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory proof
|
||||
ISelfVerificationRoot.DiscloseCircuitProof memory proof
|
||||
)
|
||||
public
|
||||
virtual
|
||||
@@ -91,7 +162,7 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
revert InvalidScope();
|
||||
}
|
||||
|
||||
if (_attestationId != proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX]) {
|
||||
if (!_attestationIds[proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX]]) {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
|
||||
@@ -102,9 +173,13 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
forbiddenCountriesEnabled: _verificationConfig.forbiddenCountriesEnabled,
|
||||
forbiddenCountriesListPacked: _verificationConfig.forbiddenCountriesListPacked,
|
||||
ofacEnabled: _verificationConfig.ofacEnabled,
|
||||
vcAndDiscloseProof: proof
|
||||
vcAndDiscloseProof: IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof({
|
||||
a: proof.a,
|
||||
b: proof.b,
|
||||
c: proof.c,
|
||||
pubSignals: proof.pubSignals
|
||||
})
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,10 +5,7 @@ import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeE
|
||||
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
|
||||
import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol";
|
||||
import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol";
|
||||
import {IIdentityVerificationHubV1} from "../interfaces/IIdentityVerificationHubV1.sol";
|
||||
import {IVcAndDiscloseCircuitVerifier} from "../interfaces/IVcAndDiscloseCircuitVerifier.sol";
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {CircuitConstants} from "../constants/CircuitConstants.sol";
|
||||
|
||||
/**
|
||||
* @title Airdrop (Experimental)
|
||||
@@ -77,6 +74,12 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
event ClaimClose();
|
||||
|
||||
event UserIdentifierRegistered(uint256 indexed registeredUserIdentifier, uint256 indexed nullifier);
|
||||
/// @notice Emitted when the scope is updated.
|
||||
event ScopeUpdated(uint256 newScope);
|
||||
/// @notice Emitted when a new attestation ID is added.
|
||||
event AttestationIdAdded(uint256 attestationId);
|
||||
/// @notice Emitted when an attestation ID is removed.
|
||||
event AttestationIdRemoved(uint256 attestationId);
|
||||
|
||||
// ====================================================
|
||||
// Constructor
|
||||
@@ -88,34 +91,19 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
* and sets the ERC20 token to be distributed.
|
||||
* @param _identityVerificationHub The address of the Identity Verification Hub.
|
||||
* @param _scope The expected proof scope for user registration.
|
||||
* @param _attestationId The expected attestation identifier required in proofs.
|
||||
* @param _attestationIds The expected attestation identifiers required in proofs.
|
||||
* @param _token The address of the ERC20 token for airdrop.
|
||||
* @param _olderThanEnabled Flag indicating if 'olderThan' verification is enabled.
|
||||
* @param _olderThan Value for 'olderThan' verification.
|
||||
* @param _forbiddenCountriesEnabled Flag indicating if forbidden countries verification is enabled.
|
||||
* @param _forbiddenCountriesListPacked Packed list of forbidden countries.
|
||||
* @param _ofacEnabled Array of flags indicating which OFAC checks are enabled. [passportNo, nameAndDob, nameAndYob]
|
||||
*/
|
||||
constructor(
|
||||
address _identityVerificationHub,
|
||||
uint256 _scope,
|
||||
uint256 _attestationId,
|
||||
address _token,
|
||||
bool _olderThanEnabled,
|
||||
uint256 _olderThan,
|
||||
bool _forbiddenCountriesEnabled,
|
||||
uint256[4] memory _forbiddenCountriesListPacked,
|
||||
bool[3] memory _ofacEnabled
|
||||
uint256[] memory _attestationIds,
|
||||
address _token
|
||||
)
|
||||
SelfVerificationRoot(
|
||||
_identityVerificationHub,
|
||||
_scope,
|
||||
_attestationId,
|
||||
_olderThanEnabled,
|
||||
_olderThan,
|
||||
_forbiddenCountriesEnabled,
|
||||
_forbiddenCountriesListPacked,
|
||||
_ofacEnabled
|
||||
_attestationIds
|
||||
)
|
||||
Ownable(_msgSender())
|
||||
{
|
||||
@@ -143,7 +131,37 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
function setVerificationConfig(
|
||||
ISelfVerificationRoot.VerificationConfig memory newVerificationConfig
|
||||
) external onlyOwner {
|
||||
_verificationConfig = newVerificationConfig;
|
||||
_setVerificationConfig(newVerificationConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Updates the scope used for verification.
|
||||
* @dev Only callable by the contract owner.
|
||||
* @param newScope The new scope to set.
|
||||
*/
|
||||
function setScope(uint256 newScope) external onlyOwner {
|
||||
_setScope(newScope);
|
||||
emit ScopeUpdated(newScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Adds a new attestation ID to the allowed list.
|
||||
* @dev Only callable by the contract owner.
|
||||
* @param attestationId The attestation ID to add.
|
||||
*/
|
||||
function addAttestationId(uint256 attestationId) external onlyOwner {
|
||||
_addAttestationId(attestationId);
|
||||
emit AttestationIdAdded(attestationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Removes an attestation ID from the allowed list.
|
||||
* @dev Only callable by the contract owner.
|
||||
* @param attestationId The attestation ID to remove.
|
||||
*/
|
||||
function removeAttestationId(uint256 attestationId) external onlyOwner {
|
||||
_removeAttestationId(attestationId);
|
||||
emit AttestationIdRemoved(attestationId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +206,7 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
* @param proof The VC and Disclose proof data used to verify and register the user.
|
||||
*/
|
||||
function verifySelfProof(
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory proof
|
||||
ISelfVerificationRoot.DiscloseCircuitProof memory proof
|
||||
)
|
||||
public
|
||||
override
|
||||
@@ -197,38 +215,21 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
if (!isRegistrationOpen) {
|
||||
revert RegistrationNotOpen();
|
||||
}
|
||||
|
||||
if (_scope != proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_SCOPE_INDEX]) {
|
||||
revert InvalidScope();
|
||||
}
|
||||
|
||||
if (_attestationId != proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX]) {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
|
||||
if (_nullifiers[proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_NULLIFIER_INDEX]] != 0) {
|
||||
if (_nullifiers[proof.pubSignals[NULLIFIER_INDEX]] != 0) {
|
||||
revert RegisteredNullifier();
|
||||
}
|
||||
|
||||
if (proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX] == 0) {
|
||||
if (proof.pubSignals[USER_IDENTIFIER_INDEX] == 0) {
|
||||
revert InvalidUserIdentifier();
|
||||
}
|
||||
|
||||
IIdentityVerificationHubV1.VcAndDiscloseVerificationResult memory result = _identityVerificationHub.verifyVcAndDisclose(
|
||||
IIdentityVerificationHubV1.VcAndDiscloseHubProof({
|
||||
olderThanEnabled: _verificationConfig.olderThanEnabled,
|
||||
olderThan: _verificationConfig.olderThan,
|
||||
forbiddenCountriesEnabled: _verificationConfig.forbiddenCountriesEnabled,
|
||||
forbiddenCountriesListPacked: _verificationConfig.forbiddenCountriesListPacked,
|
||||
ofacEnabled: _verificationConfig.ofacEnabled,
|
||||
vcAndDiscloseProof: proof
|
||||
})
|
||||
);
|
||||
super.verifySelfProof(proof);
|
||||
|
||||
_nullifiers[result.nullifier] = proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX];
|
||||
_registeredUserIdentifiers[proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX]] = true;
|
||||
_nullifiers[proof.pubSignals[NULLIFIER_INDEX]] = proof.pubSignals[USER_IDENTIFIER_INDEX];
|
||||
_registeredUserIdentifiers[proof.pubSignals[USER_IDENTIFIER_INDEX]] = true;
|
||||
|
||||
emit UserIdentifierRegistered(proof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX], result.nullifier);
|
||||
emit UserIdentifierRegistered(proof.pubSignals[USER_IDENTIFIER_INDEX], proof.pubSignals[NULLIFIER_INDEX]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,11 +241,12 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the expected attestation identifier.
|
||||
* @return The attestation identifier.
|
||||
* @notice Checks if the specified attestation ID is allowed.
|
||||
* @param attestationId The attestation ID to check.
|
||||
* @return True if the attestation ID is allowed, false otherwise.
|
||||
*/
|
||||
function getAttestationId() external view returns (uint256) {
|
||||
return _attestationId;
|
||||
function isAttestationIdAllowed(uint256 attestationId) external view returns (bool) {
|
||||
return _attestationIds[attestationId];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +263,7 @@ contract Airdrop is SelfVerificationRoot, Ownable {
|
||||
* @return The verification configuration used for registration.
|
||||
*/
|
||||
function getVerificationConfig() external view returns (ISelfVerificationRoot.VerificationConfig memory) {
|
||||
return _verificationConfig;
|
||||
return _getVerificationConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
216
contracts/contracts/example/SelfPassportERC721.sol
Normal file
216
contracts/contracts/example/SelfPassportERC721.sol
Normal file
@@ -0,0 +1,216 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol";
|
||||
import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol";
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import {SelfCircuitLibrary} from "../libraries/SelfCircuitLibrary.sol";
|
||||
|
||||
/**
|
||||
* @title SelfPassportERC721
|
||||
* @notice This contract issues ERC721 tokens based on verified passport credentials using self's verification infrastructure
|
||||
* @dev Inherits from SelfVerificationRoot for verification logic and ERC721 for NFT functionality
|
||||
*/
|
||||
contract SelfPassportERC721 is SelfVerificationRoot, ERC721, Ownable {
|
||||
using SelfCircuitLibrary for uint256[3];
|
||||
|
||||
// ====================================================
|
||||
// Storage Variables
|
||||
// ====================================================
|
||||
|
||||
/// @notice Counter for token IDs
|
||||
uint256 private _tokenIdCounter;
|
||||
|
||||
/// @notice Mapping from token ID to passport attributes
|
||||
mapping(uint256 => SelfCircuitLibrary.PassportData) private _passportAttributes;
|
||||
|
||||
/// @notice Mapping to track used nullifiers
|
||||
mapping(uint256 => bool) private _usedNullifiers;
|
||||
|
||||
// ====================================================
|
||||
// Events
|
||||
// ====================================================
|
||||
|
||||
event PassportNFTMinted(
|
||||
uint256 indexed tokenId,
|
||||
address indexed owner,
|
||||
SelfCircuitLibrary.PassportData attributes
|
||||
);
|
||||
|
||||
/// @notice Emitted when the scope is updated
|
||||
event ScopeUpdated(uint256 newScope);
|
||||
|
||||
/// @notice Emitted when a new attestation ID is added
|
||||
event AttestationIdAdded(uint256 attestationId);
|
||||
|
||||
/// @notice Emitted when an attestation ID is removed
|
||||
event AttestationIdRemoved(uint256 attestationId);
|
||||
|
||||
// ====================================================
|
||||
// Errors
|
||||
// ====================================================
|
||||
|
||||
error NullifierAlreadyUsed();
|
||||
error RegistrationNotOpen();
|
||||
error InvalidUserIdentifier();
|
||||
|
||||
// ====================================================
|
||||
// Constructor
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Constructor for the SelfPassportERC721 contract
|
||||
* @param identityVerificationHub The address of the Identity Verification Hub
|
||||
* @param scope The expected proof scope for user registration
|
||||
* @param attestationIds The expected attestation identifiers required in proofs
|
||||
* @param name The name of the NFT collection
|
||||
* @param symbol The symbol of the NFT collection
|
||||
*/
|
||||
constructor(
|
||||
address identityVerificationHub,
|
||||
uint256 scope,
|
||||
uint256[] memory attestationIds,
|
||||
string memory name,
|
||||
string memory symbol
|
||||
)
|
||||
SelfVerificationRoot(identityVerificationHub, scope, attestationIds)
|
||||
ERC721(name, symbol)
|
||||
Ownable(_msgSender())
|
||||
{}
|
||||
|
||||
// ====================================================
|
||||
// External/Public Functions
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Updates the scope used for verification
|
||||
* @dev Only callable by the contract owner
|
||||
* @param newScope The new scope to set
|
||||
*/
|
||||
function setScope(uint256 newScope) external onlyOwner {
|
||||
_setScope(newScope);
|
||||
emit ScopeUpdated(newScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Adds a new attestation ID to the allowed list
|
||||
* @dev Only callable by the contract owner
|
||||
* @param attestationId The attestation ID to add
|
||||
*/
|
||||
function addAttestationId(uint256 attestationId) external onlyOwner {
|
||||
_addAttestationId(attestationId);
|
||||
emit AttestationIdAdded(attestationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Removes an attestation ID from the allowed list
|
||||
* @dev Only callable by the contract owner
|
||||
* @param attestationId The attestation ID to remove
|
||||
*/
|
||||
function removeAttestationId(uint256 attestationId) external onlyOwner {
|
||||
_removeAttestationId(attestationId);
|
||||
emit AttestationIdRemoved(attestationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Updates the verification configuration
|
||||
* @dev Only callable by the contract owner
|
||||
* @param verificationConfig The new verification configuration
|
||||
*/
|
||||
function setVerificationConfig(
|
||||
ISelfVerificationRoot.VerificationConfig memory verificationConfig
|
||||
) external onlyOwner {
|
||||
_setVerificationConfig(verificationConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Verifies a self-proof and mints an NFT with passport attributes
|
||||
* @param proof The VC and Disclose proof data used to verify and register the user
|
||||
*/
|
||||
function verifySelfProof(
|
||||
ISelfVerificationRoot.DiscloseCircuitProof memory proof
|
||||
) public override {
|
||||
if (_usedNullifiers[proof.pubSignals[NULLIFIER_INDEX]]) {
|
||||
revert NullifierAlreadyUsed();
|
||||
}
|
||||
|
||||
if (proof.pubSignals[USER_IDENTIFIER_INDEX] == 0) {
|
||||
revert InvalidUserIdentifier();
|
||||
}
|
||||
|
||||
// Verify the proof using the parent contract's logic
|
||||
super.verifySelfProof(proof);
|
||||
|
||||
// Extract passport attributes from the revealed data using the utility function
|
||||
uint256[3] memory revealedDataPacked = getRevealedDataPacked(proof.pubSignals);
|
||||
|
||||
// Extract passport data using SelfCircuitLibrary
|
||||
SelfCircuitLibrary.PassportData memory attributes = SelfCircuitLibrary.extractPassportData(revealedDataPacked);
|
||||
|
||||
// Mint NFT
|
||||
uint256 tokenId = _tokenIdCounter++;
|
||||
_mint(msg.sender, tokenId);
|
||||
_passportAttributes[tokenId] = attributes;
|
||||
_usedNullifiers[proof.pubSignals[NULLIFIER_INDEX]] = true;
|
||||
|
||||
emit PassportNFTMinted(tokenId, msg.sender, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get passport attributes for a specific token ID
|
||||
* @param tokenId The token ID to query
|
||||
* @return The passport attributes associated with the token
|
||||
*/
|
||||
function getPassportAttributes(uint256 tokenId) external view returns (SelfCircuitLibrary.PassportData memory) {
|
||||
require(_exists(tokenId), "Token does not exist");
|
||||
return _passportAttributes[tokenId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Check if a nullifier has been used
|
||||
* @param nullifier The nullifier to check
|
||||
* @return True if the nullifier has been used, false otherwise
|
||||
*/
|
||||
function isNullifierUsed(uint256 nullifier) external view returns (bool) {
|
||||
return _usedNullifiers[nullifier];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Check if the specified attestation ID is allowed
|
||||
* @param attestationId The attestation ID to check
|
||||
* @return True if the attestation ID is allowed, false otherwise
|
||||
*/
|
||||
function isAttestationIdAllowed(uint256 attestationId) external view returns (bool) {
|
||||
return _attestationIds[attestationId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the current scope value
|
||||
* @return The current scope value
|
||||
*/
|
||||
function getScope() external view returns (uint256) {
|
||||
return _scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the current verification configuration
|
||||
* @return The current verification configuration
|
||||
*/
|
||||
function getVerificationConfig() external view returns (ISelfVerificationRoot.VerificationConfig memory) {
|
||||
return _getVerificationConfig();
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Internal Functions
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Check if a token exists
|
||||
* @param tokenId The token ID to check
|
||||
* @return True if the token exists, false otherwise
|
||||
*/
|
||||
function _exists(uint256 tokenId) internal view returns (bool) {
|
||||
return _ownerOf(tokenId) != address(0);
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,8 @@ interface IIdentityVerificationHubV1 {
|
||||
EXPIRY_DATE, // The passport expiry date.
|
||||
OLDER_THAN, // The "older than" age verification value.
|
||||
PASSPORT_NO_OFAC, // The passport number OFAC status.
|
||||
NAME_AND_DOB_OFAC, // The name and date of birth OFAC status.
|
||||
NAME_AND_YOB_OFAC // The name and year of birth OFAC status.
|
||||
NAME_AND_DOB_OFAC, // The name and date of birth OFAC verification result.
|
||||
NAME_AND_YOB_OFAC // The name and year of birth OFAC verification result.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,9 +12,20 @@ interface ISelfVerificationRoot {
|
||||
uint256[4] forbiddenCountriesListPacked;
|
||||
bool[3] ofacEnabled;
|
||||
}
|
||||
|
||||
struct DiscloseCircuitProof {
|
||||
uint256[2] a;
|
||||
uint256[2][2] b;
|
||||
uint256[2] c;
|
||||
uint256[21] pubSignals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Verifies a self-proof
|
||||
* @param proof The proof data for verification and disclosure
|
||||
*/
|
||||
function verifySelfProof(
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory proof
|
||||
DiscloseCircuitProof memory proof
|
||||
) external;
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.28;
|
||||
|
||||
import {IVcAndDiscloseCircuitVerifier} from "../interfaces/IVcAndDiscloseCircuitVerifier.sol";
|
||||
import {CircuitConstants} from "../constants/CircuitConstants.sol";
|
||||
import {Formatter} from "./Formatter.sol";
|
||||
|
||||
|
||||
223
contracts/contracts/libraries/SelfCircuitLibrary.sol
Normal file
223
contracts/contracts/libraries/SelfCircuitLibrary.sol
Normal file
@@ -0,0 +1,223 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.28;
|
||||
|
||||
import {Formatter} from "./Formatter.sol";
|
||||
import {CircuitAttributeHandler} from "./CircuitAttributeHandler.sol";
|
||||
|
||||
/**
|
||||
* @title SelfCircuitLibrary
|
||||
* @notice A user-friendly wrapper library for handling passport verification and formatting
|
||||
* @dev This library provides simplified interfaces for common operations using CircuitAttributeHandler and Formatter
|
||||
*/
|
||||
library SelfCircuitLibrary {
|
||||
/**
|
||||
* @notice Represents passport attributes in a more user-friendly format
|
||||
*/
|
||||
struct PassportData {
|
||||
string issuingState;
|
||||
string[] name; // [firstName, lastName]
|
||||
string passportNumber;
|
||||
string nationality;
|
||||
string dateOfBirth;
|
||||
string gender;
|
||||
string expiryDate;
|
||||
uint256 olderThan;
|
||||
bool passportNoOfac;
|
||||
bool nameAndDobOfac;
|
||||
bool nameAndYobOfac;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Extracts and formats passport data from packed revealed data
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return PassportData struct containing all formatted passport attributes
|
||||
*/
|
||||
function extractPassportData(uint256[3] memory revealedDataPacked) internal pure returns (PassportData memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
|
||||
return PassportData({
|
||||
issuingState: CircuitAttributeHandler.getIssuingState(charcodes),
|
||||
name: CircuitAttributeHandler.getName(charcodes),
|
||||
passportNumber: CircuitAttributeHandler.getPassportNumber(charcodes),
|
||||
nationality: CircuitAttributeHandler.getNationality(charcodes),
|
||||
dateOfBirth: CircuitAttributeHandler.getDateOfBirth(charcodes),
|
||||
gender: CircuitAttributeHandler.getGender(charcodes),
|
||||
expiryDate: CircuitAttributeHandler.getExpiryDate(charcodes),
|
||||
olderThan: CircuitAttributeHandler.getOlderThan(charcodes),
|
||||
passportNoOfac: CircuitAttributeHandler.getPassportNoOfac(charcodes) == 1,
|
||||
nameAndDobOfac: CircuitAttributeHandler.getNameAndDobOfac(charcodes) == 1,
|
||||
nameAndYobOfac: CircuitAttributeHandler.getNameAndYobOfac(charcodes) == 1
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the issuing state from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string The issuing state
|
||||
*/
|
||||
function getIssuingState(uint256[3] memory revealedDataPacked) internal pure returns (string memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getIssuingState(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves and formats the name from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string[] Array containing [firstName, lastName]
|
||||
*/
|
||||
function getName(uint256[3] memory revealedDataPacked) internal pure returns (string[] memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getName(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the passport number from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string The passport number
|
||||
*/
|
||||
function getPassportNumber(uint256[3] memory revealedDataPacked) internal pure returns (string memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getPassportNumber(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the nationality from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string The nationality
|
||||
*/
|
||||
function getNationality(uint256[3] memory revealedDataPacked) internal pure returns (string memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getNationality(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves and formats the date of birth from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string The formatted date of birth
|
||||
*/
|
||||
function getDateOfBirth(uint256[3] memory revealedDataPacked) internal pure returns (string memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getDateOfBirth(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the gender from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string The gender
|
||||
*/
|
||||
function getGender(uint256[3] memory revealedDataPacked) internal pure returns (string memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getGender(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves and formats the passport expiry date from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return string The formatted passport expiry date
|
||||
*/
|
||||
function getExpiryDate(uint256[3] memory revealedDataPacked) internal pure returns (string memory) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getExpiryDate(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the 'older than' age attribute from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return uint256 The extracted age
|
||||
*/
|
||||
function getOlderThan(uint256[3] memory revealedDataPacked) internal pure returns (uint256) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getOlderThan(charcodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the passport number OFAC status from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return bool True if passport number is not on OFAC list
|
||||
*/
|
||||
function getPassportNoOfac(uint256[3] memory revealedDataPacked) internal pure returns (bool) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getPassportNoOfac(charcodes) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the name and date of birth OFAC status from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return bool True if name and DOB are not on OFAC list
|
||||
*/
|
||||
function getNameAndDobOfac(uint256[3] memory revealedDataPacked) internal pure returns (bool) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getNameAndDobOfac(charcodes) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the name and year of birth OFAC status from the encoded attribute byte array
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @return bool True if name and YOB are not on OFAC list
|
||||
*/
|
||||
function getNameAndYobOfac(uint256[3] memory revealedDataPacked) internal pure returns (bool) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.getNameAndYobOfac(charcodes) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Checks if a passport holder meets age requirements
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @param minimumAge The minimum age requirement
|
||||
* @return bool True if the passport holder is at least minimumAge years old
|
||||
*/
|
||||
function compareOlderThan(uint256[3] memory revealedDataPacked, uint256 minimumAge) internal pure returns (bool) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.compareOlderThan(charcodes, minimumAge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Performs OFAC checks with simplified interface
|
||||
* @param revealedDataPacked An array of three packed uint256 values containing the passport data
|
||||
* @param checkPassportNo Whether to check passport number against OFAC
|
||||
* @param checkNameAndDob Whether to check name and date of birth against OFAC
|
||||
* @param checkNameAndYob Whether to check name and year of birth against OFAC
|
||||
* @return bool True if all enabled checks pass
|
||||
*/
|
||||
function compareOfac(
|
||||
uint256[3] memory revealedDataPacked,
|
||||
bool checkPassportNo,
|
||||
bool checkNameAndDob,
|
||||
bool checkNameAndYob
|
||||
) internal pure returns (bool) {
|
||||
bytes memory charcodes = Formatter.fieldElementsToBytes(revealedDataPacked);
|
||||
return CircuitAttributeHandler.compareOfac(
|
||||
charcodes,
|
||||
checkPassportNo,
|
||||
checkNameAndDob,
|
||||
checkNameAndYob
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Converts a date string to Unix timestamp
|
||||
* @param dateString Date string in YYMMDD format
|
||||
* @return uint256 Unix timestamp
|
||||
*/
|
||||
function dateToTimestamp(string memory dateString) internal pure returns (uint256) {
|
||||
return Formatter.dateToUnixTimestamp(dateString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Formats a date string from YYMMDD to DD-MM-YY
|
||||
* @param dateString Date string in YYMMDD format
|
||||
* @return string Formatted date string in DD-MM-YY format
|
||||
*/
|
||||
function formatDate(string memory dateString) internal pure returns (string memory) {
|
||||
return Formatter.formatDate(dateString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Formats a full name string into first name and last name
|
||||
* @param fullName Full name string in "lastName<<firstName" format
|
||||
* @return string[] Array containing [firstName, lastName]
|
||||
*/
|
||||
function formatName(string memory fullName) internal pure returns (string[] memory) {
|
||||
return Formatter.formatName(fullName);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,20 @@
|
||||
{
|
||||
"name": "@openpassport/contracts",
|
||||
"name": "@selfxyz/contracts",
|
||||
"version": "0.0.7",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zk-passport/openpassport"
|
||||
"url": "https://github.com/selfxyz/self"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "motemotech <i.am.nicoshark@gmail.com>",
|
||||
"files": [
|
||||
"contracts/constants/*",
|
||||
"contracts/interfaces/*",
|
||||
"contracts/constants/*",
|
||||
"contracts/libraries/*",
|
||||
"contracts/proxy/*",
|
||||
"contracts/registry/*",
|
||||
"contracts/verifiers/*",
|
||||
"contracts/IdentityVerificationHub.sol",
|
||||
"contracts/IdentityVerificationHubImplV1.sol",
|
||||
"contracts/utils/PCR0Manager.sol"
|
||||
"contracts/abstract/*"
|
||||
],
|
||||
"scripts": {
|
||||
"compile": "npx hardhat clean && npx hardhat compile",
|
||||
"build": "npx hardhat clean && npx hardhat compile",
|
||||
"deploy:all:localhost": "npm run deploy:verifiers:localhost && npm run deploy:registry:localhost && npm run deploy:hub:localhost",
|
||||
"deploy:hub:localhost": "npx hardhat ignition deploy ignition/modules/deployHub.ts --network localhost --verify",
|
||||
"deploy:registry:localhost": "npx hardhat ignition deploy ignition/modules/deployRegistry.ts --network localhost --verify",
|
||||
|
||||
@@ -63,12 +63,13 @@ const errorSignatures = [
|
||||
'INVALID_REVEALED_DATA_TYPE()',
|
||||
'HUB_NOT_SET()',
|
||||
'ONLY_HUB_CAN_ACCESS()',
|
||||
'REGISTERED_COMMITMENT()'
|
||||
'REGISTERED_COMMITMENT()',
|
||||
'RegisteredNullifier()'
|
||||
];
|
||||
|
||||
errorSignatures.forEach(sig => {
|
||||
// Pls input the error code
|
||||
const errorCode = '0x9003ac4d';
|
||||
const errorCode = '0x22cbc6a2';
|
||||
const selector = ethers.id(sig).slice(0, 10);
|
||||
if (selector === errorCode) {
|
||||
console.log(`Found matching error: ${sig}`);
|
||||
|
||||
@@ -13,6 +13,7 @@ import BalanceTree from "../utils/example/balance-tree";
|
||||
import { castFromScope } from "../../../common/src/utils/circuits/uuid";
|
||||
import { formatCountriesList, reverseBytes } from '../../../common/src/utils/circuits/formatInputs';
|
||||
import { Formatter } from "../utils/formatter";
|
||||
import { hashEndpointWithScope } from "../../../common/src/utils/scope";
|
||||
|
||||
describe("Airdrop", () => {
|
||||
let deployedActors: DeployedActors;
|
||||
@@ -27,12 +28,14 @@ describe("Airdrop", () => {
|
||||
let nullifier: any;
|
||||
let forbiddenCountriesList: any;
|
||||
let countriesListPacked: any;
|
||||
let attestationIds: any[];
|
||||
|
||||
before(async () => {
|
||||
deployedActors = await deploySystemFixtures();
|
||||
|
||||
registerSecret = generateRandomFieldElement();
|
||||
nullifier = generateRandomFieldElement();
|
||||
attestationIds = [BigInt(ATTESTATION_ID.E_PASSPORT)];
|
||||
commitment = generateCommitment(registerSecret, ATTESTATION_ID.E_PASSPORT, deployedActors.mockPassport);
|
||||
|
||||
forbiddenCountriesList = ['AAA', 'ABC', 'CBA'];
|
||||
@@ -45,7 +48,7 @@ describe("Airdrop", () => {
|
||||
registerSecret,
|
||||
BigInt(ATTESTATION_ID.E_PASSPORT).toString(),
|
||||
deployedActors.mockPassport,
|
||||
"test-airdrop",
|
||||
hashEndpointWithScope("https://test.com", "test-scope"),
|
||||
new Array(88).fill("1"),
|
||||
"1",
|
||||
imt,
|
||||
@@ -73,17 +76,21 @@ describe("Airdrop", () => {
|
||||
const airdropFactory = await ethers.getContractFactory("Airdrop");
|
||||
airdrop = await airdropFactory.connect(deployedActors.owner).deploy(
|
||||
deployedActors.hub.target,
|
||||
castFromScope("test-airdrop"),
|
||||
ATTESTATION_ID.E_PASSPORT,
|
||||
token.target,
|
||||
true,
|
||||
20,
|
||||
true,
|
||||
countriesListPacked,
|
||||
[true, true, true],
|
||||
hashEndpointWithScope("https://test.com", "test-scope"),
|
||||
attestationIds,
|
||||
token.target
|
||||
);
|
||||
await airdrop.waitForDeployment();
|
||||
|
||||
const verificationConfig = {
|
||||
olderThanEnabled: true,
|
||||
olderThan: 20,
|
||||
forbiddenCountriesEnabled: true,
|
||||
forbiddenCountriesListPacked: countriesListPacked,
|
||||
ofacEnabled: [true, true, true] as [boolean, boolean, boolean]
|
||||
};
|
||||
await airdrop.connect(deployedActors.owner).setVerificationConfig(verificationConfig);
|
||||
|
||||
const mintAmount = ethers.parseEther("424242424242");
|
||||
await token.mint(airdrop.target, mintAmount);
|
||||
|
||||
@@ -234,11 +241,17 @@ describe("Airdrop", () => {
|
||||
registerSecret,
|
||||
BigInt(ATTESTATION_ID.E_PASSPORT).toString(),
|
||||
deployedActors.mockPassport,
|
||||
"test-airdrop-invalid",
|
||||
hashEndpointWithScope("https://test.com", "test-scope-invalid"),
|
||||
new Array(88).fill("1"),
|
||||
"1",
|
||||
imt,
|
||||
"20",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
forbiddenCountriesList,
|
||||
(await deployedActors.user1.getAddress()).slice(2)
|
||||
);
|
||||
|
||||
await airdrop.connect(owner).openRegistration();
|
||||
@@ -275,11 +288,17 @@ describe("Airdrop", () => {
|
||||
registerSecret,
|
||||
BigInt(ATTESTATION_ID.INVALID_ATTESTATION_ID).toString(),
|
||||
deployedActors.mockPassport,
|
||||
"test-airdrop",
|
||||
hashEndpointWithScope("https://test.com", "test-scope"),
|
||||
new Array(88).fill("1"),
|
||||
"1",
|
||||
invalidImt,
|
||||
"20",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
forbiddenCountriesList,
|
||||
(await deployedActors.user1.getAddress()).slice(2)
|
||||
);
|
||||
|
||||
await airdrop.connect(owner).openRegistration();
|
||||
@@ -294,13 +313,15 @@ describe("Airdrop", () => {
|
||||
registerSecret,
|
||||
BigInt(ATTESTATION_ID.E_PASSPORT).toString(),
|
||||
deployedActors.mockPassport,
|
||||
"test-airdrop",
|
||||
hashEndpointWithScope("https://test.com", "test-scope"),
|
||||
new Array(88).fill("1"),
|
||||
"1",
|
||||
imt,
|
||||
"20",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
forbiddenCountriesList,
|
||||
"0000000000000000000000000000000000000000"
|
||||
);
|
||||
@@ -316,17 +337,21 @@ describe("Airdrop", () => {
|
||||
const airdropFactory = await ethers.getContractFactory("Airdrop");
|
||||
const newAirdrop = await airdropFactory.connect(owner).deploy(
|
||||
hub.target,
|
||||
castFromScope("test-airdrop"),
|
||||
ATTESTATION_ID.E_PASSPORT,
|
||||
token.target,
|
||||
true,
|
||||
20,
|
||||
true,
|
||||
countriesListPacked,
|
||||
[true, true, true],
|
||||
hashEndpointWithScope("https://test.com", "test-scope"),
|
||||
attestationIds,
|
||||
token.target
|
||||
);
|
||||
await newAirdrop.waitForDeployment();
|
||||
|
||||
const verificationConfig = {
|
||||
olderThanEnabled: true,
|
||||
olderThan: 20,
|
||||
forbiddenCountriesEnabled: true,
|
||||
forbiddenCountriesListPacked: countriesListPacked,
|
||||
ofacEnabled: [true, true, true] as [boolean, boolean, boolean]
|
||||
};
|
||||
await newAirdrop.connect(owner).setVerificationConfig(verificationConfig);
|
||||
|
||||
await newAirdrop.connect(owner).openRegistration();
|
||||
await expect(newAirdrop.connect(user1).verifySelfProof(vcAndDiscloseProof))
|
||||
.to.not.be.reverted;
|
||||
@@ -334,12 +359,15 @@ describe("Airdrop", () => {
|
||||
|
||||
it("should return correct scope", async () => {
|
||||
const scope = await airdrop.getScope();
|
||||
expect(scope).to.equal(castFromScope("test-airdrop"));
|
||||
expect(scope).to.equal(hashEndpointWithScope("https://test.com", "test-scope"));
|
||||
});
|
||||
|
||||
it("should return correct attestation id", async () => {
|
||||
const attestationId = await airdrop.getAttestationId();
|
||||
expect(attestationId).to.equal(ATTESTATION_ID.E_PASSPORT);
|
||||
it("should check if attestation ID is allowed", async () => {
|
||||
const isAllowed = await airdrop.isAttestationIdAllowed(ATTESTATION_ID.E_PASSPORT);
|
||||
expect(isAllowed).to.be.true;
|
||||
|
||||
const isNotAllowed = await airdrop.isAttestationIdAllowed(999999); // Some random ID not in the list
|
||||
expect(isNotAllowed).to.be.false;
|
||||
});
|
||||
|
||||
it("should return correct merkle root", async () => {
|
||||
@@ -511,7 +539,7 @@ describe("Airdrop", () => {
|
||||
olderThan: 25,
|
||||
forbiddenCountriesEnabled: false,
|
||||
forbiddenCountriesListPacked: countriesListPacked,
|
||||
ofacEnabled: [false, false, false]
|
||||
ofacEnabled: [false, false, false] as [boolean, boolean, boolean]
|
||||
};
|
||||
|
||||
await airdrop.connect(owner).setVerificationConfig(newVerificationConfig);
|
||||
@@ -533,7 +561,7 @@ describe("Airdrop", () => {
|
||||
olderThan: 25,
|
||||
forbiddenCountriesEnabled: false,
|
||||
forbiddenCountriesListPacked: countriesListPacked,
|
||||
ofacEnabled: [false, false, false]
|
||||
ofacEnabled: [false, false, false] as [boolean, boolean, boolean]
|
||||
};
|
||||
|
||||
await expect(airdrop.connect(user1).setVerificationConfig(newVerificationConfig))
|
||||
@@ -552,4 +580,76 @@ describe("Airdrop", () => {
|
||||
expect(config.ofacEnabled).to.deep.equal([true, true, true]);
|
||||
});
|
||||
|
||||
it("should able to update scope by owner", async () => {
|
||||
const { owner } = deployedActors;
|
||||
const newScope = hashEndpointWithScope("https://newtest.com", "new-test-scope");
|
||||
|
||||
await airdrop.connect(owner).setScope(newScope);
|
||||
const scope = await airdrop.getScope();
|
||||
expect(scope).to.equal(newScope);
|
||||
|
||||
// Verify event was emitted
|
||||
const filter = airdrop.filters.ScopeUpdated();
|
||||
const events = await airdrop.queryFilter(filter);
|
||||
const lastEvent = events[events.length - 1];
|
||||
expect(lastEvent.args.newScope).to.equal(newScope);
|
||||
});
|
||||
|
||||
it("should not be able to update scope by non-owner", async () => {
|
||||
const { user1 } = deployedActors;
|
||||
const newScope = hashEndpointWithScope("https://newtest.com", "new-test-scope");
|
||||
|
||||
await expect(airdrop.connect(user1).setScope(newScope))
|
||||
.to.be.revertedWithCustomError(airdrop, "OwnableUnauthorizedAccount")
|
||||
.withArgs(await user1.getAddress());
|
||||
});
|
||||
|
||||
it("should able to add attestation ID by owner", async () => {
|
||||
const { owner } = deployedActors;
|
||||
const newAttestationId = 999; // Some new ID
|
||||
|
||||
await airdrop.connect(owner).addAttestationId(newAttestationId);
|
||||
const isAllowed = await airdrop.isAttestationIdAllowed(newAttestationId);
|
||||
expect(isAllowed).to.be.true;
|
||||
|
||||
// Verify event was emitted
|
||||
const filter = airdrop.filters.AttestationIdAdded();
|
||||
const events = await airdrop.queryFilter(filter);
|
||||
const lastEvent = events[events.length - 1];
|
||||
expect(lastEvent.args.attestationId).to.equal(newAttestationId);
|
||||
});
|
||||
|
||||
it("should not be able to add attestation ID by non-owner", async () => {
|
||||
const { user1 } = deployedActors;
|
||||
const newAttestationId = 888; // Some new ID
|
||||
|
||||
await expect(airdrop.connect(user1).addAttestationId(newAttestationId))
|
||||
.to.be.revertedWithCustomError(airdrop, "OwnableUnauthorizedAccount")
|
||||
.withArgs(await user1.getAddress());
|
||||
});
|
||||
|
||||
it("should able to remove attestation ID by owner", async () => {
|
||||
const { owner } = deployedActors;
|
||||
const attestationIdToRemove = ATTESTATION_ID.E_PASSPORT;
|
||||
|
||||
await airdrop.connect(owner).removeAttestationId(attestationIdToRemove);
|
||||
const isAllowed = await airdrop.isAttestationIdAllowed(attestationIdToRemove);
|
||||
expect(isAllowed).to.be.false;
|
||||
|
||||
// Verify event was emitted
|
||||
const filter = airdrop.filters.AttestationIdRemoved();
|
||||
const events = await airdrop.queryFilter(filter);
|
||||
const lastEvent = events[events.length - 1];
|
||||
expect(lastEvent.args.attestationId).to.equal(attestationIdToRemove);
|
||||
});
|
||||
|
||||
it("should not be able to remove attestation ID by non-owner", async () => {
|
||||
const { user1 } = deployedActors;
|
||||
const attestationIdToRemove = ATTESTATION_ID.E_PASSPORT;
|
||||
|
||||
await expect(airdrop.connect(user1).removeAttestationId(attestationIdToRemove))
|
||||
.to.be.revertedWithCustomError(airdrop, "OwnableUnauthorizedAccount")
|
||||
.withArgs(await user1.getAddress());
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
11628
contracts/yarn.lock
11628
contracts/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user