Skip to content

Commit 790a378

Browse files
authored
Add virtune-token endpoint to por-address-list (#3996)
* Add virtune-token endpoint to por-address-list * virtune-token test changes * Copy integration test * Changes to integration test
1 parent 00f44a3 commit 790a378

File tree

10 files changed

+554
-80
lines changed

10 files changed

+554
-80
lines changed

.changeset/famous-yaks-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@chainlink/por-address-list-adapter': minor
3+
---
4+
5+
Add virtune-token endpoint compatible with token-balance

packages/sources/por-address-list/src/endpoint/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export { endpoint as multichainAddress } from './multichainAddress'
55
export { endpoint as openedenAddress } from './openEdenUSDOAddress'
66
export { endpoint as solvBTC } from './solvBTC'
77
export { endpoint as virtune } from './virtune'
8+
export { endpoint as virtuneToken } from './virtune-token'
89
export { endpoint as zeusBtcAddress } from './zeusBTC'
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
2+
import { PoRTokenAddress } from '@chainlink/external-adapter-framework/adapter/por'
3+
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
4+
import { config } from '../config'
5+
import { virtuneTokenTransport } from '../transport/virtune-token'
6+
7+
export const inputParameters = new InputParameters(
8+
{
9+
accountId: {
10+
description: 'The account ID to fetch addresses for',
11+
type: 'string',
12+
required: true,
13+
},
14+
network: {
15+
description:
16+
'The network the addresses are on. This is only used to include in the response.',
17+
type: 'string',
18+
required: true,
19+
},
20+
chainId: {
21+
description:
22+
'The chainId of the network the addresses are on. This is only used to include in the response.',
23+
type: 'string',
24+
required: true,
25+
},
26+
contractAddress: {
27+
description: 'The contract address of the token, to pass be included in the response',
28+
type: 'string',
29+
default: '',
30+
},
31+
},
32+
[
33+
{
34+
accountId: 'VIRBTC',
35+
network: 'ethereum',
36+
chainId: '1',
37+
contractAddress: '0x514910771af9ca656af840dff83e8264ecf986ca',
38+
},
39+
],
40+
)
41+
42+
export type BaseEndpointTypes = {
43+
Parameters: typeof inputParameters.definition
44+
Response: {
45+
Result: null
46+
Data: {
47+
result: PoRTokenAddress[]
48+
}
49+
}
50+
Settings: typeof config.settings
51+
}
52+
53+
// This endpoint is similar to the virtune endpoint but returns a response in a
54+
// format that proof-of-reserves can pass on to token-balance.
55+
export const endpoint = new AdapterEndpoint({
56+
name: 'virtune-token',
57+
transport: virtuneTokenTransport,
58+
inputParameters,
59+
})

packages/sources/por-address-list/src/endpoint/virtune.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export type BaseEndpointTypes = {
4444
Settings: typeof config.settings
4545
}
4646

47+
// This endpoint is similar to the virtune-token endpoint but returns a
48+
// response in a format that proof-of-reserves can pass on to por-indexer or
49+
// ethereum-cl-indexer.
4750
export const endpoint = new AdapterEndpoint({
4851
name: 'virtune',
4952
transport: virtuneTransport,

packages/sources/por-address-list/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
openedenAddress,
1010
solvBTC,
1111
virtune,
12+
virtuneToken,
1213
zeusBtcAddress,
1314
} from './endpoint'
1415

@@ -24,6 +25,7 @@ export const adapter = new PoRAdapter({
2425
multichainAddress,
2526
openedenAddress,
2627
virtune,
28+
virtuneToken,
2729
zeusBtcAddress,
2830
],
2931
rateLimiting: {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { PoRTokenAddress } from '@chainlink/external-adapter-framework/adapter/por'
2+
import {
3+
HttpTransport,
4+
HttpTransportConfig,
5+
} from '@chainlink/external-adapter-framework/transports'
6+
import { BaseEndpointTypes } from '../endpoint/virtune-token'
7+
import { createVirtuneTransportConfig, ResponseSchema, VirtuneParams } from './virtune-utils'
8+
export type HttpTransportTypes = BaseEndpointTypes & {
9+
Provider: {
10+
RequestBody: never
11+
ResponseBody: ResponseSchema
12+
}
13+
}
14+
15+
type Params = VirtuneParams<HttpTransportTypes>
16+
17+
const getUrl = (params: Params): string => {
18+
return params.accountId
19+
}
20+
21+
const getAddresses = ({
22+
data,
23+
params,
24+
}: {
25+
data: ResponseSchema
26+
params: Params
27+
}): PoRTokenAddress[] => {
28+
const { network, chainId, contractAddress } = params
29+
const wallets = data.result.flatMap((r) => r.wallets.map((w) => w.address))
30+
if (wallets.length === 0) {
31+
return []
32+
}
33+
return [
34+
{
35+
chainId,
36+
network,
37+
contractAddress,
38+
wallets,
39+
},
40+
]
41+
}
42+
43+
const transportConfig: HttpTransportConfig<HttpTransportTypes> =
44+
createVirtuneTransportConfig<HttpTransportTypes>(getUrl, getAddresses)
45+
46+
// Exported for testing
47+
export class VirtuneTokenTransport extends HttpTransport<HttpTransportTypes> {
48+
constructor() {
49+
super(transportConfig)
50+
}
51+
}
52+
53+
export const virtuneTokenTransport = new VirtuneTokenTransport()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`execute virtune should return success 1`] = `
4+
{
5+
"data": {
6+
"result": [
7+
{
8+
"chainId": "mainnet",
9+
"contractAddress": "0x514910771af9ca656af840dff83e8264ecf986ca",
10+
"network": "bitcoin",
11+
"wallets": [
12+
"1JSYkxvBJy4wXDskdXfadfTj6Hg9n5r3br",
13+
"17ABiL5ToFwYdjGtVngEXo2Bw4EKN5myTT",
14+
],
15+
},
16+
],
17+
},
18+
"result": null,
19+
"statusCode": 200,
20+
"timestamps": {
21+
"providerDataReceivedUnixMs": 978347471111,
22+
"providerDataRequestedUnixMs": 978347471111,
23+
},
24+
}
25+
`;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {
2+
TestAdapter,
3+
setEnvVariables,
4+
} from '@chainlink/external-adapter-framework/util/testing-utils'
5+
import nock from 'nock'
6+
import { mockVirtuneResponseSuccess } from './fixtures-api'
7+
8+
describe('execute', () => {
9+
let spy: jest.SpyInstance
10+
let testAdapter: TestAdapter
11+
let oldEnv: NodeJS.ProcessEnv
12+
13+
beforeAll(async () => {
14+
oldEnv = JSON.parse(JSON.stringify(process.env))
15+
process.env.RPC_URL = process.env.RPC_URL ?? 'http://localhost:8080'
16+
process.env.VIRTUNE_API_URL = 'http://virtune'
17+
process.env.VIRTUNE_API_KEY = 'virtuneApiKey'
18+
process.env.BACKGROUND_EXECUTE_MS = '0'
19+
20+
const mockDate = new Date('2001-01-01T11:11:11.111Z')
21+
spy = jest.spyOn(Date, 'now').mockReturnValue(mockDate.getTime())
22+
23+
const adapter = (await import('./../../src')).adapter
24+
adapter.rateLimiting = undefined
25+
testAdapter = await TestAdapter.startWithMockedCache(adapter, {
26+
testAdapter: {} as TestAdapter<never>,
27+
})
28+
})
29+
30+
afterAll(async () => {
31+
setEnvVariables(oldEnv)
32+
await testAdapter.api.close()
33+
nock.restore()
34+
nock.cleanAll()
35+
spy.mockRestore()
36+
})
37+
38+
describe('virtune', () => {
39+
it('should return success', async () => {
40+
const data = {
41+
endpoint: 'virtune-token',
42+
accountId: 'VIRBTC',
43+
network: 'bitcoin',
44+
chainId: 'mainnet',
45+
contractAddress: '0x514910771af9ca656af840dff83e8264ecf986ca',
46+
}
47+
48+
mockVirtuneResponseSuccess()
49+
50+
const response = await testAdapter.request(data)
51+
52+
expect(response.statusCode).toBe(200)
53+
expect(response.json()).toMatchSnapshot()
54+
})
55+
})
56+
})

0 commit comments

Comments
 (0)