Skip to content

Commit

Permalink
completing API for kleros verifications
Browse files Browse the repository at this point in the history
  • Loading branch information
pellicceama committed Oct 25, 2022
1 parent 46852ca commit 25ce210
Show file tree
Hide file tree
Showing 13 changed files with 707 additions and 6,423 deletions.
3,647 changes: 324 additions & 3,323 deletions .pnp.cjs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
"axios": "^0.27.2",
"csv-parse": "^5.3.0",
"ethereum-checksum-address": "^0.0.8",
"ethers": "^5.7.2",
"jsonschema": "^1.4.1",
"shelljs": "^0.8.5",
"uuid": "^8.3.2",
"web3": "^1.8.0"
"uuid": "^8.3.2"
},
"packageManager": "[email protected]",
"repository": {
Expand Down
1 change: 0 additions & 1 deletion src/model/Asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ async function enhanceExtTokenInfoWithSourceData(baseToken: Asset, chainId: numb
return baseToken;
}


switch(source) {
case 'trustwallet':
return getTwaTokenInfo(baseToken, chainId);
Expand Down
12 changes: 2 additions & 10 deletions src/model/Verification.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
export interface Verification {
verified: boolean;
type: VerificationType;
timestamp: number;
proof: VerificationProof;
}

type VerificationProof = AdminVerificationProof | KlerosTCRVerificationProof | Map3TCRVerificationProof | Map3MapsTcrVerificationProof;
type VerificationProof = AdminVerificationProof | TCRVerificationProof;

interface AdminVerificationProof {
signature: string;
}

interface KlerosTCRVerificationProof {
ipfsUri: string;
}

interface Map3TCRVerificationProof {
ipfsUri: string;
interface TCRVerificationProof {
resolutionTxHash: string;
chainId: number;
}

interface Map3MapsTcrVerificationProof extends Map3TCRVerificationProof { }

export type VerificationType = 'ADMIN' | 'KLEROS_TCR' | 'MAP3_TCR' | 'MAP3_MAPS_TCR';
2 changes: 1 addition & 1 deletion src/tokenlist/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export async function ingestTokenList(listLocation: string, directory: string, b

if(newAssets.length > 0) {
await branch(directory, branchName);
await ingestNewAssets(newAssets, directory, source, verificationType);
await ingestNewAssets(newAssets, directory, source);
await needBeRegenerateTokenlist(directory);
await commit(directory, `Indexing ${listToIngest.tokens.length} new assets from ${listToIngest.name || source}`);
}
Expand Down
13 changes: 5 additions & 8 deletions src/utils/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ export function formatAddress(address: string): string {
return address.toLowerCase();
}

// extracts a contract address from a CAIP-19 asset types
// https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-19.md#test-cases
export function getAddressFromAssetId(assetId: string): string {
const address = assetId.split(':')[2];
if(!address) {
throw new Error('Invalid assetId');
export function parseAssetId(assetId: string): { networkCode: string, address: string } {
const [networkCode, address] = assetId.split(':');
return {
networkCode,
address: parseInt(address) == 0? undefined : formatAddress(address)
}

return address;
}
19 changes: 5 additions & 14 deletions src/utils/ipfs.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import Web3 from 'web3';
import { ethers } from "ethers";
import axios from 'axios';

export async function getEnsIpfsContentHash(ens: string): Promise<string> {
export async function getEnsIpfsContentHash(ens: string, rpcProviderUrl: string): Promise<string> {
try {
const web3 = new Web3(process.env.ALCHEMY_MAINNET_URL + '');
const record = await web3.eth.ens.getContenthash(ens);
const provider = new ethers.providers.JsonRpcProvider(rpcProviderUrl + '', 'homestead');
const resolver = await provider.getResolver(ens);

if(record.protocolType !== 'ipfs') {
throw new Error('Invalid protocol type');
}

if(!record.decoded) {
throw new Error('Decoded content hash is null');
}

return record.decoded;

return resolver.getText('ipfs');
} catch (err: any) {
throw err;
}
Expand Down
59 changes: 12 additions & 47 deletions src/utils/tcrs/kleros-tcr.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,42 @@
import { TokenList } from "@uniswap/token-lists";
import axios from "axios";
import { getAddressFromAssetId } from "../addresses";
import { getEnsIpfsContentHash, getIpfsContent } from "../ipfs";
import { parseAssetId } from "../addresses";
import { TcrCheckResult } from "./types";

interface KlerosTcrCache {
tokenlist: TokenList,
lastUpdated: number,
ipfsHash: string
}
let cache: KlerosTcrCache = {
tokenlist: null,
lastUpdated: 0,
ipfsHash: null
}

async function needBeUpdateCache() {
if (Date.now() - cache.lastUpdated > 1000 * 60 * 60) {
const KLEROS_ENS_ENS_DOMAIN = 't2crtokens.eth';
const ipfsHash = await getEnsIpfsContentHash(KLEROS_ENS_ENS_DOMAIN);

cache.tokenlist = await getIpfsContent(ipfsHash);
cache.lastUpdated = Date.now();
}
}

export async function checkIfAssetInKlerosTCR(assetId: string): Promise<TcrCheckResult> {

try {
await needBeUpdateCache();
const address = getAddressFromAssetId(assetId);

const tokenInTcr = cache.tokenlist.tokens.some((token: any) => token.address === address);

if(!tokenInTcr) {
return {
inTcr: false,
ipfsUri: null,
resolutionTxHash: null
}
}
try {
const { networkCode, address } = parseAssetId(assetId);

const query = {
query: `
query GetKlerosTcrTokenByAddress {
tokens(where: {address: ${address}}) {
const query = `
query { tokens(where: { address: "${address}" }) {
address
status
ticker
name
requests(orderBy: resolutionTime, orderDirection: desc, first: 1) {
resolutionTx
}
}
}
`
};
} }
`;

const url = 'https://api.thegraph.com/subgraphs/name/kleros/t2cr';
const response = await axios.post(url, { query });
const response = await axios.post(url, { query: query }, { headers: { 'Content-Type': 'application/json' } });

if(response.data.errors) {
throw new Error(response.data.errors.map((e: any) => e.message).join(', '));
}
const token = response.data.data.tokens[0];

if(!token) {
return {
inTcr: false,
ipfsUri: null,
resolutionTxHash: null
}
}

return {
inTcr: token.status === 'Registered',
ipfsUri: cache.ipfsHash,
resolutionTxHash: token.requests[0].resolutionTx
}
} catch (e) {
Expand Down
4 changes: 0 additions & 4 deletions src/utils/tcrs/map-tcrs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export async function checkIfMapInMapsTcr(map: AssetMap): Promise<TcrCheckResult

return {
inTcr: response.data.status === 'Registered',
ipfsUri: response.data.ipfs_uri,
resolutionTxHash: response.data.resolution_tx
}

Expand All @@ -20,7 +19,6 @@ export async function checkIfMapInMapsTcr(map: AssetMap): Promise<TcrCheckResult

return {
inTcr: false,
ipfsUri: null,
resolutionTxHash: null
}
}
Expand All @@ -37,7 +35,6 @@ export async function checkIfAssetInMap3TCR(assetId: string): Promise<TcrCheckRe

return {
inTcr: response.data.status === 'Registered',
ipfsUri: response.data.ipfs_uri,
resolutionTxHash: response.data.resolution_tx
}

Expand All @@ -46,7 +43,6 @@ export async function checkIfAssetInMap3TCR(assetId: string): Promise<TcrCheckRe

return {
inTcr: false,
ipfsUri: null,
resolutionTxHash: null
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/utils/tcrs/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export interface TcrCheckResult {
inTcr: boolean,
ipfsUri: string,
resolutionTxHash: string
resolutionTxHash: string
}
14 changes: 14 additions & 0 deletions src/utils/verification.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import test from "ava";
import { attemptTcrVerificationForAsset } from "./verifications";

const USDC_ON_ETH = 'ethereum:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';

test("Check if USDC is is set as verified on Kleros TCR", async (t) => {
try {
const result = await attemptTcrVerificationForAsset('ethereum', USDC_ON_ETH);

t.true(result.verified);
} catch (err) {
t.fail(err.message);
}
});
73 changes: 44 additions & 29 deletions src/utils/verifications.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,71 @@
import { AssetMap } from "../model/AssetMap";
import { Verification } from "../model/Verification";
import { checkIfAssetInKlerosTCR } from "./tcrs/kleros-tcr";

export interface VerificationAttemptResult {
verified: boolean;
verification: Verification;
verifications: Verification[];
}

export function setAdminVerificationForAsset(signature: string, networkCode: string, address?: string): Verification {
export async function setAdminVerificationForAsset(signature: string, networkCode: string, address?: string): Promise<VerificationAttemptResult> {
// TODO; signature operation
return {
verified: true,
type: 'ADMIN',
timestamp: Date.now() / 1000,
proof: {
signature: '0x'
}
verified: false,
verifications: []
}
}

export function setAdminVerificationForMap(signature: string, map: AssetMap): Verification {
export async function setAdminVerificationForMap(signature: string, map: AssetMap): Promise<VerificationAttemptResult> {

// TODO; signature operation
return {
verified: true,
type: 'ADMIN',
timestamp: Date.now() / 1000,
proof: {
signature: '0x'
}
verified: false,
verifications: []
}
}

export function attemptTcrVerificationForAsset(networkCode: string, address?: string): Verification {
export async function attemptTcrVerificationForAsset(networkCode: string, address?: string): Promise<VerificationAttemptResult> {
// If ethereum, check the kleros tcr and map3 tcr to see if its verified and produce the verification. Otherwise just the map3tcr
return {
verified: true,
type: 'KLEROS_TCR',
timestamp: Date.now() / 1000,
proof: {
ipfsUri: 'ipfs://QmWJ7CpY6hJkLjyYQ2zEeY2YJZ9XgZK1n8JWd7vP6oKJjK'

if(networkCode !== 'ethereum' || !address) {
throw new Error(`Invalid network code or address for TCR verification`);
}

try {
const klerosTcrResult = await checkIfAssetInKlerosTCR(address);

if(!klerosTcrResult.inTcr) {
return {
verified: false,
verifications: []
}
}

return {
verified: true,
verifications: [{
verified: true,
type: 'KLEROS_TCR',
proof: {
resolutionTxHash: klerosTcrResult.resolutionTxHash,
chainId: 1
}
}]
}

} catch (err) {
console.error(err);
return {
verified: false,
verifications: []
}
}
}

export function attemptTcrVerificationForMap(map: AssetMap): Verification {
export async function attemptTcrVerificationForMap(map: AssetMap): Promise<VerificationAttemptResult> {
// Check the map3 maps tcr to see if its verified and produce the verification
return {
verified: true,
type: 'KLEROS_TCR',
timestamp: Date.now() / 1000,
proof: {
ipfsUri: 'ipfs://QmWJ7CpY6hJkLjyYQ2zEeY2YJZ9XgZK1n8JWd7vP6oKJjK'
}
verified: false,
verifications: []
}
}
Loading

0 comments on commit 25ce210

Please sign in to comment.