For Developers Clean Hands How to read Clean Hands attestations
Zeronym issues its Clean Hands attestation to users who prove that they are not on any sanctions lists.
Off-chain with Sign Protocol
Use Sign Protocol's scan API to see whether a user has a valid Clean Hands attestation.
Copy // Set user address
const address = '0x123'
const resp = await fetch(`https://mainnet-rpc.sign.global/api/scan/addresses/${address}/attestations`)
const data = await resp.json()
const cleanHandsAttestations = data.data.rows.filter((att) => (
att.fullSchemaId == 'onchain_evm_10_0x8' &&
att.attester == '0xB1f50c6C34C72346b1229e5C80587D0D659556Fd' &&
att.isReceiver == true &&
!att.revoked &&
att.validUntil > (new Date().getTime() / 1000)
))
const hasValidAttestation = cleanHandsAttestations.length > 0
On Optimism with Sign Protocol
Tutorial coming soon...
On-chain (not Optimism)
Use our off-chain attester, and verify its signature on-chain. Our attester returns a signature of the circuit ID, action ID, and user address, if the address has a clean hands attestation.
Our attester address is 0xa74772264f896843c6346ceA9B13e0128A1d3b5D
.
Query for signature
Copy // Set user address
const userAddress = '0x123'
const actionId = 123456789
const resp = await fetch(`https://api.holonym.io/attestation/sbts/clean-hands?action-id=${actionId}&address=${userAddress}`)
const { isUnique, signature, circuitId } = await resp.json();
Verify signature in Solidity
Warning: this Solidity code is untested.
Copy pragma solidity ^0.8.4;
import "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
contract SignatureVerification {
using ECDSA for bytes32;
address public zeronymAttester = 0xa74772264f896843c6346ceA9B13e0128A1d3b5D;
function verifySignature(
uint256 circuitId,
uint256 actionId,
address userAddress,
bytes memory signature
) public pure returns (bool) {
bytes32 digest = keccak256(abi.encodePacked(
circuitId,
actionId,
userAddress
));
bytes32 personalSignPreimage = keccak256(abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
digest
));
(
address recovered,
ECDSA.RecoverError err,
bytes32 _sig
) = ECDSA.tryRecover(personalSignPreimage, publicSignalsSig);
return recovered == zeronymAttester;
}
}
Verify signature in JavaScript
Copy // Verify using ethers v5
const digest = ethers.utils.solidityKeccak256(
["uint256", "uint256", "address"],
[circuitId, actionId, userAddress]
);
const personalSignPreimage = ethers.utils.solidityKeccak256(
["string", "bytes32"],
["\x19Ethereum Signed Message:\n32", digest]
);
const recovered = ethers.utils.recoverAddress(personalSignPreimage, signature)
console.log(recovered === '0xa74772264f896843c6346ceA9B13e0128A1d3b5D')
Decrypt
See Decryption of Provably Encrypted Data .
Last updated 2 months ago