Skip to content

Commit

Permalink
feat: verifier issuer check contract exists (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nebulis authored Feb 5, 2020
1 parent 286b6bb commit 61406e8
Show file tree
Hide file tree
Showing 37 changed files with 1,577 additions and 1,146 deletions.
53 changes: 40 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
"dependencies": {
"@govtechsg/dnsprove": "^2.0.5",
"@govtechsg/open-attestation": "3.1.0",
"ethers": "^4.0.40"
"debug": "^4.1.1",
"ethers": "^4.0.44"
},
"devDependencies": {
"@commitlint/cli": "8.2.0",
"@commitlint/config-conventional": "8.2.0",
"@commitlint/prompt": "8.2.0",
"@ls-age/commitlint-circle": "1.0.0",
"@types/debug": "^4.1.5",
"@types/jest": "^24.0.23",
"@typescript-eslint/eslint-plugin": "1.6.0",
"@typescript-eslint/parser": "^2.11.0",
Expand Down
19 changes: 19 additions & 0 deletions src/common/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import debug from "debug";

const logger = debug("oa-verify");

interface Logger {
trace: debug.Debugger;
debug: debug.Debugger;
info: debug.Debugger;
warn: debug.Debugger;
error: debug.Debugger;
}

export const getLogger = (namespace: string): Logger => ({
trace: logger.extend(`trace:${namespace}`),
debug: logger.extend(`debug:${namespace}`),
info: logger.extend(`info:${namespace}`),
warn: logger.extend(`warn:${namespace}`),
error: logger.extend(`error:${namespace}`)
});
21 changes: 0 additions & 21 deletions src/common/smartContract/contractInstance.test.ts

This file was deleted.

20 changes: 15 additions & 5 deletions src/common/smartContract/contractInstance.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import * as ethers from "ethers";
import { INFURA_API_KEY } from "../../config";
import { Hash } from "../../types/core";
import { getLogger } from "../logger";

const logger = getLogger("contractInstance");
interface ContractInstance {
abi: any; // type is any of json file in abi folder
network: string;
contractAddress: Hash;
}

export const getProvider = (options: { network: string }): ethers.providers.Provider =>
new ethers.providers.InfuraProvider(options.network, INFURA_API_KEY);

export const contractInstance = (options: ContractInstance) => {
return new ethers.Contract(
options.contractAddress,
options.abi,
new ethers.providers.InfuraProvider(options.network, INFURA_API_KEY)
);
const contract = new ethers.Contract(options.contractAddress, options.abi, getProvider(options));

// this is done to prevent uncaught exception to raise because an address is invalid
contract.addressPromise.catch(() => {
logger.trace(
`oa-verify caught an error from ethers when trying to resolve the address of the provided address ${options.contractAddress}`
);
});
return contract;
};
31 changes: 31 additions & 0 deletions src/common/smartContract/documentStoreContractInterface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Contract } from "ethers";
import { getData, v2, v3, WrappedDocument } from "@govtechsg/open-attestation";
import { Hash, isWrappedV2Document } from "../../types/core";
import { contractInstance } from "./contractInstance";
import documentStoreAbi from "./abi/documentStore.json";

export const getIssuersDocumentStore = (
document: WrappedDocument<v2.OpenAttestationDocument> | WrappedDocument<v3.OpenAttestationDocument>
): string[] => {
if (isWrappedV2Document(document)) {
const data = getData(document);
return data.issuers.map(issuer => issuer.documentStore || issuer.certificateStore || "");
}
return [getData(document).proof.value];
};

export const createDocumentStoreContract = (address: string, { network }: { network: string }) => {
return contractInstance({
contractAddress: address,
abi: documentStoreAbi,
network
});
};

export const isIssuedOnDocumentStore = async (smartContract: Contract, hash: Hash): Promise<boolean> => {
return smartContract.functions.isIssued(hash);
};

export const isRevokedOnDocumentStore = async (smartContract: Contract, hash: Hash): Promise<boolean> => {
return smartContract.functions.isRevoked(hash);
};
67 changes: 67 additions & 0 deletions src/common/smartContract/documentStoreErrors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { errors } from "ethers";
import {
EthersError,
Hash,
OpenAttestationEthereumDocumentStoreIssuedCode,
OpenAttestationEthereumDocumentStoreRevokedCode,
Reason
} from "../..";

const contractNotFound = (address: Hash): Reason => {
return {
code: OpenAttestationEthereumDocumentStoreIssuedCode.CONTRACT_NOT_FOUND,
codeString:
OpenAttestationEthereumDocumentStoreIssuedCode[OpenAttestationEthereumDocumentStoreIssuedCode.CONTRACT_NOT_FOUND],
message: `Contract ${address} was not found`
};
};
const contractAddressInvalid = (address: Hash): Reason => {
return {
code: OpenAttestationEthereumDocumentStoreIssuedCode.CONTRACT_ADDRESS_INVALID,
codeString:
OpenAttestationEthereumDocumentStoreIssuedCode[
OpenAttestationEthereumDocumentStoreIssuedCode.CONTRACT_ADDRESS_INVALID
],
message: `Contract address ${address} is invalid`
};
};
export const contractNotIssued = (merkleRoot: Hash, address: string): Reason => {
return {
code: OpenAttestationEthereumDocumentStoreIssuedCode.DOCUMENT_NOT_ISSUED,
codeString:
OpenAttestationEthereumDocumentStoreIssuedCode[
OpenAttestationEthereumDocumentStoreIssuedCode.DOCUMENT_NOT_ISSUED
],
message: `Certificate ${merkleRoot} has not been issued under contract ${address}`
};
};

export const contractRevoked = (merkleRoot: string, address: string): Reason => {
return {
code: OpenAttestationEthereumDocumentStoreRevokedCode.DOCUMENT_REVOKED,
codeString:
OpenAttestationEthereumDocumentStoreRevokedCode[OpenAttestationEthereumDocumentStoreRevokedCode.DOCUMENT_REVOKED],
message: `Certificate ${merkleRoot} has been revoked under contract ${address}`
};
};

export const getErrorReason = (error: EthersError, address: string): Reason | null => {
const reason = error.reason && Array.isArray(error.reason) ? error.reason[0] : error.reason ?? "";
if (reason.toLowerCase() === "contract not deployed".toLowerCase() && error.code === errors.UNSUPPORTED_OPERATION) {
return contractNotFound(address);
} else if (
(reason.toLowerCase() === "ENS name not configured".toLowerCase() && error.code === errors.UNSUPPORTED_OPERATION) ||
(reason.toLowerCase() === "bad address checksum".toLowerCase() && error.code === errors.INVALID_ARGUMENT) ||
(reason.toLowerCase() === "invalid address".toLowerCase() && error.code === errors.INVALID_ARGUMENT)
) {
return contractAddressInvalid(address);
}
return {
message: `Error with smart contract ${address}: ${error.reason}`,
code: OpenAttestationEthereumDocumentStoreIssuedCode.ETHERS_UNHANDLED_ERROR,
codeString:
OpenAttestationEthereumDocumentStoreIssuedCode[
OpenAttestationEthereumDocumentStoreIssuedCode.ETHERS_UNHANDLED_ERROR
]
};
};
81 changes: 0 additions & 81 deletions src/common/smartContract/documentToSmartContracts.ts

This file was deleted.

Loading

0 comments on commit 61406e8

Please sign in to comment.