UNPKG

@0xpolygonid/js-sdk

Version:
144 lines (125 loc) 4.35 kB
import { RevocationStatus, Issuer } from '../../verifiable'; import { Contract, JsonRpcProvider, Signer, TransactionReceipt, TransactionRequest } from 'ethers'; import { Proof, NodeAuxJSON, Hash } from '@iden3/js-merkletree'; import { EthConnectionConfig } from './state'; import abi from '../blockchain/abi/CredentialStatusResolver.json'; import { ITransactionService, TransactionService } from '../../blockchain'; /** * OnChainRevocationStore is a class that allows to interact with the onchain contract * and build the revocation status. * * @public * @class OnChainIssuer */ export class OnChainRevocationStorage { private readonly _contract: Contract; private readonly _provider: JsonRpcProvider; private readonly _transactionService: ITransactionService; /** * * Creates an instance of OnChainIssuer. * @public * @param {string} - onchain contract address * @param {string} - rpc url to connect to the blockchain */ constructor( private readonly _config: EthConnectionConfig, contractAddress: string, private _signer?: Signer ) { this._provider = new JsonRpcProvider(_config.url); let contract = new Contract(contractAddress, abi, this._provider); if (this._signer) { this._signer = this._signer.connect(this._provider); contract = contract.connect(this._signer) as Contract; } this._contract = contract; this._transactionService = new TransactionService(this._provider); } /** * Get revocation status by issuerId, issuerState and nonce from the onchain. * @public * @returns Promise<RevocationStatus> */ public async getRevocationStatusByIdAndState( issuerID: bigint, state: bigint, nonce: number ): Promise<RevocationStatus> { const response = await this._contract.getRevocationStatusByIdAndState(issuerID, state, nonce); const issuer = OnChainRevocationStorage.convertIssuerInfo(response.issuer); const mtp = OnChainRevocationStorage.convertSmtProofToProof(response.mtp); return { issuer, mtp }; } /** * Get revocation status by nonce from the onchain contract. * @public * @returns Promise<RevocationStatus> */ public async getRevocationStatus(issuerID: bigint, nonce: number): Promise<RevocationStatus> { const response = await this._contract.getRevocationStatus(issuerID, nonce); const issuer = OnChainRevocationStorage.convertIssuerInfo(response.issuer); const mtp = OnChainRevocationStorage.convertSmtProofToProof(response.mtp); return { issuer, mtp }; } public async saveNodes(payload: bigint[][]): Promise<TransactionReceipt> { if (!this._signer) { throw new Error('No signer provided'); } const feeData = await this._provider.getFeeData(); const maxFeePerGas = this._config.maxFeePerGas ? BigInt(this._config.maxFeePerGas) : feeData.maxFeePerGas; const maxPriorityFeePerGas = this._config.maxPriorityFeePerGas ? BigInt(this._config.maxPriorityFeePerGas) : feeData.maxPriorityFeePerGas; const gasLimit = await this._contract.saveNodes.estimateGas(payload); const txData = await this._contract.saveNodes.populateTransaction(payload); const request: TransactionRequest = { to: txData.to, data: txData.data, gasLimit, maxFeePerGas, maxPriorityFeePerGas }; const { txnReceipt } = await this._transactionService.sendTransactionRequest( this._signer, request ); return txnReceipt; } private static convertIssuerInfo(issuer: bigint[]): Issuer { const [state, claimsTreeRoot, revocationTreeRoot, rootOfRoots] = issuer.map((i) => Hash.fromBigInt(i).hex() ); return { state, claimsTreeRoot, revocationTreeRoot, rootOfRoots }; } private static convertSmtProofToProof(mtp: { existence: boolean; auxIndex: bigint; auxValue: bigint; auxExistence: boolean; siblings: bigint[]; }): Proof { let nodeAux: NodeAuxJSON | undefined = undefined; const siblings = mtp.siblings?.map((s) => s.toString()); if (mtp.auxExistence) { nodeAux = { key: mtp.auxIndex.toString(), value: mtp.auxValue.toString() }; } return Proof.fromJSON({ existence: mtp.existence, node_aux: nodeAux, siblings }); } }