2. API Response

Once the verification by the issuer is completed (ex: KYC verification, AML verification, etc..), the issuers is responsible for generating a standardized API response.

Attributes in the Quadrata Passport are standardized to enable interoperability between issuers.

Response API Payload

{
  'contractParameters': {
     'account': '',
     'attrKeys': [],
     'attrValues': [],
     'attrTypes' [],
     'fee': '',
     'verifiedAt': '',
     'issuedAt': '',
     'chainId': '',
     'signature': '',
     'did': '',
  },
  
   // Remaining Issuer specific Response Payload
}

account

Wallet address of the user to verify

attrKeys

List of attribute identifiers linking the attribute type and the account.

This list has to be the same length as attrValues and attrTypes and in the same exact order


const { utils } = require("ethers");
import { BytesLike } from '@ethersproject/bytes';

const computeAttrKeys = (account: string, attrTypes: BytesLike[]) => {
    let attrKeys: string[] = [];
    let attrKey: str;
    
    attrTypes.forEach((attrType) => {
        // For attributes set at the wallet address level (ex: COUNTRY, IS_BUSINESS, DID)
        attrKey = utils.keccak256(
        utils.defaultAbiCoder.encode(["address", "bytes32"]),
        [account, attrType]
        );
    
        // ------ OR -------- //
    
        // For attributes grouped by DID (ex: AML)
        attrKey = utils.keccak256(
            utils.defaultAbiCoder.encode(["bytes32", "bytes32"]),
            [did, attrType]
        ); 
        attrKeys.push(attrKey)
    }
    
    return attrKeys;
}

const account = "0x......"; // User Wallet Address
const attrTypes = [utils.id("COUNTRY"), utils.id("AML")]; // List of attributes to attest

const attrKeys = computeAttrKeys(account, attrTypes)

attrValues

List of attributes values. See Passport Attributes for more information.

This list has to be the same length as attrValues and attrTypes and in the same exact order

attrTypes

List of attributes types (ex: [utils.id("COUNTRY"), utils.id("AML")])

This list has to be the same length as attrValues and attrTypes and in the same exact order

fee

Fee in the native token ($ETH for Ethereum, $MATIC for Polygon) for attaching the new attributes being attested by the issuers. The fee is in Wei.

100% of the fee is redistributed to the issuer.

verifiedAt

Unix Epoch (in seconds) representing the date when the attributes has been verified by the issuer.

issuedAt

Unix Epoch (in seconds) representing the date when the attributes signature has been generated - allowing the user to mint their passport

chainId

Blockchain Network chain Id (ex: 1 for Ethereum Mainnet, 137 for Polygon). See list of chain ID.

signature

ECDSA Signature signed by the issuer to generate a verifiable proof of the attributes attested

const { Signer, DataHexString, utils, Wallet } = require("ethers");
import { BytesLike } from '@ethersproject/bytes';


export const signAttributes = async (
  accountAddress: string,
  issuer: typeof Signer,
  attrKeys: BytesLike[],
  attrValues: BytesLike[],
  verifiedAt: number,
  issuedAt: number,
  fee: any,
  passportAddress: string,
  chainId: number,
  did: BytesLike = utils.constants.HashZero,
): Promise<typeof DataHexString> => {
  const attrKeys: string[] = [];
  const attrValues: string[] = [];

  const hash = utils.keccak256(
    utils.defaultAbiCoder.encode(
      [
        "address",
        "bytes32[]",
        "bytes32[]",
        "bytes32",
        "uint256",
        "uint256",
        "uint256",
        "uint256",
        "address",
      ],
      [
        accountAddress,
        attrKeys,
        attrValues,
        did,
        verifiedAt,
        issuedAt,
        fee,
        chainId,
        passportAddress,
      ]
    )
  );

  const sig = await issuer.signMessage(utils.arrayify(hash));

  return sig;
};

const accountAddress = "0x......";  // Wallet address of the user
const issuer = new Wallet(ISSUER_PRIVATE_KEY); // Loading issuer account from their private key
const attrTypes = [utils.id("COUNTRY"), utils.id("AML")];  // List of attributes types
const attrKeys = computeAttrKeys(accountAddress, attrTypes); // List of attributes Identifiers
const attrValues = [utils.id("US"), utils.hexZeroPad("0x01", 32)]; // List of attributes values
const verifiedAt = Math.floor(new Date().getTime() / 1000) - 60; // we substract 60 seconds to avoid errors during minting passport with long block time
const issuedAt = Math.floor(new Date().getTime() / 1000) - 60; // we substract 60 seconds to avoid errors during minting passport with long block time
const passportAddress = "0x2e779749c40CC4Ba1cAB4c57eF84d90755CC017d";
const chainId = 1; // 1 for Ethereum Mainnet
const fee = utils.parseEther("0.001"); // Fee paid by the user to the issuer in then native blokcchain currency (ex: ETH for Ethereum, MATIC for Polygon)

const signature = await signAttributes(
  accountAddress,
  issuer,
  attrKeys,
  attrValues,
  verifiedAt,
  issuedAt, 
  fee,
  passportAddress,
  chainId
);

did (Optional)

The Decentralized Identifier for the wallet holders. This field is only required for passport issuers performing documentary KYC.

Last updated