From 8474e4995ebee08a1efd8764c89fbe49db7b09ab Mon Sep 17 00:00:00 2001 From: Sanjay Raveendran Date: Thu, 6 Jul 2023 16:35:43 -0700 Subject: [PATCH] Add tests for ccip resolution --- src/app.ts | 8 ++++---- src/util.ts | 4 ++-- tests/index.test.ts | 44 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/app.ts b/src/app.ts index 1ab623e1..8dec5f04 100644 --- a/src/app.ts +++ b/src/app.ts @@ -16,7 +16,7 @@ import { import { decodeDnsName } from './util.js'; -const abi = [ +export const RESOLVE_ABI = [ 'function resolve(bytes calldata name, bytes calldata data) external view returns(string name, uint256 timestamp, address owner, bytes memory sig)', ]; @@ -25,11 +25,11 @@ await migrateToLatest(db, log); const server = new ccipread.Server(); -server.add(abi, [ +server.add(RESOLVE_ABI, [ { type: 'resolve', func: async ([name, _data], _req) => { - const [fname, ..._rest] = decodeDnsName(name); + const fname = decodeDnsName(name)[0]; const transfer = await getLatestTransfer(fname, db); if (!transfer || transfer.to === 0) { // If no transfer or the name was unregistered, return empty values @@ -41,7 +41,7 @@ server.add(abi, [ }, ]); -export const app = server.makeApp('/ccip'); +export const app = server.makeApp('/ccip/'); app.get('/transfers', async (req, res) => { const filterOpts: TransferHistoryFilter = {}; diff --git a/src/util.ts b/src/util.ts index 608a5d14..0995c3b5 100644 --- a/src/util.ts +++ b/src/util.ts @@ -97,10 +97,10 @@ export function currentTimestamp(): number { } export function decodeDnsName(name: string) { - let dnsname = Buffer.from(name.slice(2), 'hex'); + const dnsname = Buffer.from(name.slice(2), 'hex'); const labels = []; let idx = 0; - while (true) { + for (;;) { const len = dnsname.readUInt8(idx); if (len === 0) break; labels.push(dnsname.slice(idx + 1, idx + len + 1).toString('utf8')); diff --git a/tests/index.test.ts b/tests/index.test.ts index 653ff51d..1847a32d 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,13 +1,12 @@ import request from 'supertest'; -import { app } from '../src/app.js'; +import { app, RESOLVE_ABI } from '../src/app.js'; import { sql } from 'kysely'; import { getDbClient, migrateToLatest } from '../src/db.js'; import { log } from '../src/log.js'; import { generateSignature, signer, signerAddress, signerFid, verifySignature } from '../src/signature.js'; -import { currentTimestamp } from '../src/util.js'; +import { bytesToHex, currentTimestamp } from '../src/util.js'; import { createTestTransfer } from './utils.js'; -import { ethers } from 'ethers'; -import { bytesToHex } from '../src/util.js'; +import { AbiCoder, ethers, Interface, ZeroAddress } from 'ethers'; const db = getDbClient(); const anotherSigner = ethers.Wallet.createRandom(); @@ -174,4 +173,41 @@ describe('app', () => { expect(response.body.signer.toLowerCase()).toEqual(signerAddress.toLowerCase()); }); }); + + describe('ccip resolution', () => { + const resolveABI = new Interface(RESOLVE_ABI).getFunction('resolve')!; + + it('should return a valid signature for a ccip lookup of a registered name', async () => { + const ccipContract = '0x4ea0be853219be8c9ce27200bdeee36881612ff2'; + // Calldata for test1.farcaster.xyz + const callData = + '0x9061b923000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000015057465737431096661726361737465720378797a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000243b3b57deeea35aa5de7e8da11d1636463a57da877fa0c0c65b969f7fecb7eb6c93a20c1b00000000000000000000000000000000000000000000000000000000'; + const response = await request(app).get(`/ccip/${ccipContract}/${callData}.json`); + // const response = await request(app).get(`/transfers?name=test3&from_ts=${now + 1}`); + expect(response.status).toBe(200); + const [username, timestamp, owner, signature] = AbiCoder.defaultAbiCoder().decode( + resolveABI.outputs, + response.body.data + ); + expect(username).toBe('test1'); + expect(verifySignature(username, timestamp, owner, signature, signer.address)).toBe(true); + }); + + it('should return an empty signature for a ccip lookup of an unregistered name', async () => { + const ccipContract = '0x4ea0be853219be8c9ce27200bdeee36881612ff2'; + // Calldata for alice.farcaster.xyz + const callData = + '0x9061b92300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001505616c696365096661726361737465720378797a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000243b3b57de00d4f449060ad2a07ff5ad355ae8da52281e95f6ad10fb923ae7cad9f2c43c2a00000000000000000000000000000000000000000000000000000000'; + const response = await request(app).get(`/ccip/${ccipContract}/${callData}.json`); + expect(response.status).toBe(200); + const [username, timestamp, owner, signature] = AbiCoder.defaultAbiCoder().decode( + resolveABI.outputs, + response.body.data + ); + expect(username).toBe(''); + expect(timestamp.toString()).toEqual('0'); + expect(owner).toBe(ZeroAddress); + expect(signature).toBe('0x'); + }); + }); });