diff --git a/README.md b/README.md index 10f008b..f142cf9 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ We plan to support more chains in the future. If you would like to use Holonym o ```JSON { "hasValidSbt": false, - "message": "SBT is expired or does not exist" + "message": "SBT is expired or does not exist" } ``` @@ -76,7 +76,7 @@ See the following documentation [How to get user's proofs](https://holonym.gitbo | name | description | type | in | required | | ----------------- | --------------------------------- | ------ | ----- | -------- | | `credential-type` | 'gov-id', 'epassport', or 'phone' | string | path | true | - | `network` | 'optimism' or 'optimism-goerli' | string | path | true | + | `network` | 'optimism' or 'base-sepolia' | string | path | true | | `user` | User's blockchain address | string | query | true | | `action-id` | Action ID | string | query | true | diff --git a/src/constants/HubV3TestnetABI.js b/src/constants/HubV3TestnetABI.js new file mode 100644 index 0000000..7b21462 --- /dev/null +++ b/src/constants/HubV3TestnetABI.js @@ -0,0 +1,20 @@ +export default [ + "function balanceOf(address) view returns (uint256)", + "function getApproved(uint256) view returns (address)", + "function getIdentifier(address,bytes32) pure returns (bytes32)", + "function getSBT(address,bytes32) view returns (tuple(uint256,uint256[],bool))", + "function isApprovedForAll(address,address) view returns (bool)", + "function name() view returns (string)", + "function owner() view returns (address)", + "function ownerOf(uint256) view returns (address)", + "function renounceOwnership()", + "function revokeSBT(address,bytes32)", + "function sbtOwners(bytes32) view returns (uint256, bool)", + "function setSBT(bytes32 circuitId, address sbtReceiver, uint expiration, uint nullifier, uint[] calldata publicValues)", + "function supportsInterface(bytes4) view returns (bool)", + "function symbol() view returns (string)", + "function tokenURI(uint256) view returns (string)", + "function transferOwnership(address)", + "function usedNullifiers(uint256) view returns (bool)", + "function getSBTByNullifier(uint256 nullifier) view returns (tuple(uint256 expiry, uint256[] publicValues, bool revoked) sbt)", +]; diff --git a/src/constants/misc.js b/src/constants/misc.js index b345d36..53e785b 100644 --- a/src/constants/misc.js +++ b/src/constants/misc.js @@ -3,6 +3,9 @@ export const defaultActionId = 123456789; export const hubV3Address = "0x2AA822e264F8cc31A2b9C22f39e5551241e94DfB"; export const hubV3Chain = 10; +export const hubV3TestnetAddress = "0x98221c937C51f5bBe615CB104435395c93b1AD8D"; +export const hubV3TestnetChain = 84532; + export const govIdIssuerAddress = "0x03fae82f38bf01d9799d57fdda64fad4ac44e4c2c2f16c5bf8e1873d0a3e1993"; export const phoneIssuerAddress = @@ -18,10 +21,10 @@ export const v3PhoneSybilResistanceCircuitId = "0xbce052cf723dca06a21bd3cf838bc518931730fb3db7859fc9cc86f0d5483495"; export const v3EPassportSybilResistanceCircuitId = "0xf2ce248b529343e105f7b3c16459da619281c5f81cf716d28f7df9f87667364d"; -export const v3CleanHandsCircuitId = +export const v3CleanHandsCircuitId = "0x1c98fc4f7f1ad3805aefa81ad25fa466f8342292accf69566b43691d12742a19"; -export const ePassportIssuerMerkleRoot = +export const ePassportIssuerMerkleRoot = "0x111abc2c2de1738067395fa944c07ce6e44c4a38accfed392797bb94cee2cdac"; export const zeronymCleanHandsEthSignSchemaId = "onchain_evm_10_0x8"; diff --git a/src/services/sybil-resistance.js b/src/services/sybil-resistance.js index 3b9e6ae..3429c92 100644 --- a/src/services/sybil-resistance.js +++ b/src/services/sybil-resistance.js @@ -10,6 +10,7 @@ import { } from "../constants/contractAddresses.js"; import { hubV3Address, + hubV3TestnetAddress, govIdIssuerAddress, phoneIssuerAddress, v3KYCSybilResistanceCircuitId, @@ -19,6 +20,67 @@ import { } from "../constants/misc.js"; import AntiSybilStoreABI from "../constants/AntiSybilStoreABI.js"; import HubV3ABI from "../constants/HubV3ABI.js"; +import HubV3TestnetABI from "../constants/HubV3TestnetABI.js"; + +// --------------------------------------------- +// Testnet stuff +// --------------------------------------------- + +async function sybilResistanceKycTestnet(req, res) { + const address = req.query.user; + const actionId = req.query["action-id"]; + if (!address) { + return res + .status(400) + .json({ error: "Request query params do not include user address" }); + } + if (!actionId) { + return res + .status(400) + .json({ error: "Request query params do not include action-id" }); + } + if (!assertValidAddress(address)) { + return res.status(400).json({ error: "Invalid user address" }); + } + if (!parseInt(actionId)) { + return res.status(400).json({ error: "Invalid action-id" }); + } + + // Check blocklist first + // const blockListResult = await blocklistGetAddress(address); + // if (blockListResult.Item) { + // return res.status(200).json({ result: false }); + // } + + // const network = req.params.network; + + const provider = providers["base-sepolia"]; + + const hubV3Contract = new ethers.Contract( + hubV3TestnetAddress, + HubV3TestnetABI, + provider + ); + + // Check v3 contract for KYC SBT + try { + const sbt = await hubV3Contract.getSBT(address, v3KYCSybilResistanceCircuitId); + + // For sandbox, we don't care about expiry or issuer or action ID. We just + // check whether the user has an SBT. + + return res.status(200).json({ result: !!sbt }); + } catch (err) { + if ((err.errorArgs?.[0] ?? "").includes("SBT is expired")) { + return res.status(200).json({ result: false }); + } + + throw err; + } +} +// --------------------------------------------- +// END: Testnet stuff +// --------------------------------------------- async function sybilResistanceGovIdNear(req, res) { const user = req.query.user; @@ -123,6 +185,8 @@ async function sybilResistanceGovId(req, res) { try { if (req.params.network === "near") { return await sybilResistanceGovIdNear(req, res); + } else if (req.params.network === "base-sepolia") { + return await sybilResistanceKycTestnet(req, res); } const address = req.query.user; diff --git a/src/services/testnet-minter.js b/src/services/testnet-minter.js index 6bcfa59..728bb40 100644 --- a/src/services/testnet-minter.js +++ b/src/services/testnet-minter.js @@ -1,6 +1,10 @@ import { randomBytes } from "crypto"; import { ethers } from "ethers"; -import { v3KYCSybilResistanceCircuitId } from "../constants/misc.js"; +import { + hubV3TestnetAddress, + v3KYCSybilResistanceCircuitId, +} from "../constants/misc.js"; +import HubV3TestnetABI from "../constants/HubV3TestnetABI.js"; import { providers } from "../init.js"; export async function setKycSbt(req, res) { @@ -12,11 +16,11 @@ export async function setKycSbt(req, res) { const { circuitId, sbtReceiver, expiration, nullifier, publicValues } = req.body; - const abi = [ - "function setSBT(bytes32 circuitId, address sbtReceiver, uint expiration, uint nullifier, uint[] calldata publicValues)", - ]; - const address = "0x98221c937C51f5bBe615CB104435395c93b1AD8D"; - const contract = new ethers.Contract(address, abi, testnetMinterWallet); + const contract = new ethers.Contract( + hubV3TestnetAddress, + HubV3TestnetABI, + testnetMinterWallet + ); const tx = await contract.setSBT( // circuitId,