Skip to content

Commit

Permalink
Added some example scripts for backend pass lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
dankelleher committed Sep 19, 2024
1 parent 7d8ff0a commit 214b444
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 9 deletions.
40 changes: 40 additions & 0 deletions packages/evm/exampleScripts/getPassStatusUsingAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Get the state of a custom pass by calling the Civic Partner API with Oauth client credentials.
// Usage: CLIENT_ID=<client-id> CLIENT_SECRET=<client-secret> bun run getPassStatusUsingAPI.ts <walletAddress> <chain>
// Full documentation: https://civicteam.github.io/openapi-docs

const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const walletAddress = process.argv[2];
const chain = process.argv[3];

// Authentication credentials for the Civic API
const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

// The Civic endpoints used to authenticate and lookup the pass status
const authUrl = "https://auth.civic.com/oauth/token";
const lookupUrl = `https://api.civic.com/partner/pass/${chain}/${walletAddress}`;

(async () => {
// fetch the oauth client credentials token
const loginResponse = await fetch(authUrl, {
headers: {
accept: "application/json, text/plain, */*",
authorization: `Basic ${basicAuth}`,
"content-type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
method: "POST"
});
const token = (await loginResponse.json()).access_token;

// now use that token to fetch the pass status
const lookupResponse = await fetch(lookupUrl, {
headers: {
accept: "application/json",
authorization: `Bearer ${token}`,
},
});

const passStatus = await lookupResponse.json();
console.log(passStatus);
})().catch((error) => console.error(error));
41 changes: 41 additions & 0 deletions packages/evm/exampleScripts/getPassStatusUsingContractABI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Get the state of a pass by calling the contract directly
// Usage: RPC=<your rpc node> bun run getPassStatusUsingContractABI.ts <walletAddress> <gatekeeperNetwork>

import {ethers} from "ethers";
import {base58ToBigInt, GATEWAY_CONTRACT_ADDRESS} from "./util";

// The script needs the wallet address and gatekeeper network as arguments
const walletAddress = process.argv[2]; // 0x...
const gatekeeperNetwork = process.argv[3]; // The gatekeeper network key in base58

// check the args - you must also provide an RPC as an environment variable
if (!walletAddress || !gatekeeperNetwork || !process.env.RPC) {
console.log('Usage: RPC=<your rpc node> bun run getPassStatusUsingContractABI.ts <walletAddress> <gatekeeperNetwork>');
process.exit(1);
}

// create the ethers provider
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC);
// converting the network key to a number for the ethereum contract
// NOTE - Pass types created before July 2024 are mapped to a slot ID in the gateway contract - these are not supported here.
// If you are using a pass type created before July 2024, contact Civic support to get the associated slot ID.
const slotId = base58ToBigInt(gatekeeperNetwork);
// A portion of the ABI. The full ABI is available here: https://github.com/civicteam/on-chain-identity-gateway/blob/main/ethereum/gateway-eth-ts/src/contracts/abi/GatewayToken.sol/GatewayToken.json
const abi = [
'function getToken(uint256) view returns (address,uint8,string,uint256,uint256)',
'function getTokenIdsByOwnerAndNetwork(address,uint256,bool) view returns (uint[])',
];

// Call the contract to get the token IDs for the wallet address and gatekeeper network
// Note - we are not using typescript here, but typescript bindings are available here:
// https://github.com/civicteam/on-chain-identity-gateway/tree/main/ethereum/gateway-eth-ts/src/contracts/typechain-types
const contract = new ethers.Contract(GATEWAY_CONTRACT_ADDRESS, abi, provider);
contract.getTokenIdsByOwnerAndNetwork(walletAddress, slotId, true).then((tokenIds: bigint[]) => {
// For each token ID, look up its state on chain.
tokenIds.forEach(async tokenId => {
const [owner, state, identity, expiration, bitmask] = await contract.getToken(tokenId);
console.log(`Token ID: ${tokenId}`);
console.log(`Pass status: ${state}`); // An enum, see details here: https://github.com/civicteam/on-chain-identity-gateway/blob/e742e9f628c0886dfbbeb43596736f0952dd64bc/ethereum/gateway-eth-ts/src/utils/types.ts#L9
console.log(`Expiration: ${expiration}`);
})
});
32 changes: 32 additions & 0 deletions packages/evm/exampleScripts/getPassStatusUsingLibrary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Get the state of a pass using the @civic/gateway-eth-ts NPM library
// Usage: RPC=<your rpc node> bun run getPassStatusUsingLibrary.ts <walletAddress> <gatekeeperNetwork>

import {GatewayTs, TokenState} from '@civic/gateway-eth-ts';
import {ethers} from "ethers";
import {base58ToBigInt, GATEWAY_CONTRACT_ADDRESS} from "./util";

// The script needs the wallet address and gatekeeper network as arguments
const walletAddress = process.argv[2]; // 0x...
const gatekeeperNetwork = process.argv[3]; // The gatekeeper network key in base58

// check the args - you must also provide an RPC as an environment variable
if (!walletAddress || !gatekeeperNetwork || !process.env.RPC) {
console.log('Usage: RPC=<your rpc node> bun run getPassStatusUsingLibrary.ts <walletAddress> <gatekeeperNetwork>');
process.exit(1);
}

// create the ethers provider and pass it into civic library
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC);
const gatewayTs = new GatewayTs(provider, GATEWAY_CONTRACT_ADDRESS)

// Get the token for the wallet address and gatekeeper network
gatewayTs.getToken(walletAddress, base58ToBigInt(gatekeeperNetwork)).then(token => {
if (!token) {
console.log('Token not found');
return;
}

console.log(`Token ID: ${token.tokenId}`);
console.log(`Pass status: ${TokenState[token.state]}`);
console.log(`Expiration: ${token.expiration}`);
});
14 changes: 14 additions & 0 deletions packages/evm/exampleScripts/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {decode} from "bs58";

const base58ToHex = (base58: string) => {
try {
return decode(base58).toString('hex');
} catch (error) {
console.log('Error decoding base58 string:', error);
throw new Error(`Invalid base58 string: ${base58}. Pass types created before July 2024 are mapped to a slot ID in the gateway contract - these are not supported here.`);
}
}
const hexToBigInt = (hex: string) => BigInt(`0x${hex}`)
export const base58ToBigInt = (base58: string) => hexToBigInt(base58ToHex(base58))

export const GATEWAY_CONTRACT_ADDRESS = '0xF65b6396dF6B7e2D8a6270E3AB6c7BB08BAEF22E';
2 changes: 2 additions & 0 deletions packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
"deploy:testnet": "hardhat deploy --network testnet"
},
"devDependencies": {
"@civic/gateway-eth-ts": "^0.8.1",
"@identity.com/gateway-protocol-eth": "^0.0.4",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.7",
"@nomicfoundation/hardhat-ethers": "^3.0.6",
"@nomicfoundation/hardhat-network-helpers": "^1.0.11",
"@nomicfoundation/hardhat-verify": "^2.0.8",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.1.0",
"@types/bs58": "^4.0.4",
"@types/chai": "^4.3.16",
"@types/mocha": "^10.0.7",
"chai": "^5.1.1",
Expand Down
25 changes: 25 additions & 0 deletions packages/solana/exampleScripts/getPassStatusUsingLibrary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Get the state of a pass using the @civic/solana-gateway-ts NPM library
// Usage: RPC=<your rpc node> bun run getPassStatusUsingLibrary.ts <walletAddress> <gatekeeperNetwork>

import {findGatewayTokensForOwnerAndNetwork} from '@civic/solana-gateway-ts';
import {Connection, PublicKey} from "@solana/web3.js";

// The script needs the wallet address and gatekeeper network as arguments
const walletAddress = process.argv[2]; // A solana public key
const gatekeeperNetwork = process.argv[3]; // The gatekeeper network key in base58

// check the args - you must also provide an RPC as an environment variable
if (!walletAddress || !gatekeeperNetwork || !process.env.RPC) {
console.log('Usage: RPC=<your rpc node> bun run getPassStatusUsingLibrary.ts <walletAddress> <gatekeeperNetwork>');
process.exit(1);
}

const connection = new Connection(process.env.RPC, 'confirmed');

// Get the token for the wallet address and gatekeeper network
findGatewayTokensForOwnerAndNetwork(connection, new PublicKey(walletAddress), new PublicKey(gatekeeperNetwork)).then((tokens) => {
tokens.forEach((token) => {
console.log(`Pass status: ${token.state}`);
console.log(`Expiration: ${token.expiryTime}`);
});
});
1 change: 1 addition & 0 deletions packages/solana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"@solana/spl-token": "^0.4.7"
},
"devDependencies": {
"@civic/solana-gateway-ts": "^0.13.0",
"@coral-xyz/anchor-cli": "^0.30.1",
"@types/bn.js": "^5.1.5",
"@types/chai": "^4.3.16",
Expand Down
Loading

0 comments on commit 214b444

Please sign in to comment.