Skip to content

Commit b414e38

Browse files
Subarna-Singhmmcallister-cllapp-token-issuer-data-feeds[bot]
authored
Coinbase cbBTC por address list (#3693)
* Coinbase cbBTC por address list * changeset * Test cases * changeset * add input params * prettier * update test case * add chainID * fix test --------- Co-authored-by: mmcallister-cll <[email protected]> Co-authored-by: app-token-issuer-data-feeds[bot] <134377064+app-token-issuer-data-feeds[bot]@users.noreply.github.com>
1 parent a7c5607 commit b414e38

File tree

9 files changed

+342
-3
lines changed

9 files changed

+342
-3
lines changed

.changeset/four-bees-battle.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+
Coinbase PoR

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ export const config = new AdapterConfig({
2424
type: 'number',
2525
default: 10_000,
2626
},
27+
COINBASE_CBBTC_API_ENDPOINT: {
28+
description: 'An API endpoint for Coinbase cbBTC native BTC wallet address',
29+
type: 'string',
30+
default: 'https://coinbase.com/cbbtc/proof-of-reserves.json',
31+
},
2732
BEDROCK_UNIBTC_API_ENDPOINT: {
2833
description: 'An API endpoint for Bedrock uniBTC native BTC wallet address',
2934
type: 'string',
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { PoRAddress } from '@chainlink/external-adapter-framework/adapter/por'
2+
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
3+
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
4+
import { config } from '../config'
5+
import { coinbaseHttpTransport } from '../transport/coinbaseBTC'
6+
7+
export const inputParameters = new InputParameters(
8+
{
9+
network: {
10+
description: 'The network name to associate with the addresses',
11+
type: 'string',
12+
required: true,
13+
},
14+
chainId: {
15+
description: 'The chain ID to associate with the addresses',
16+
type: 'string',
17+
required: true,
18+
},
19+
},
20+
[
21+
{
22+
network: 'bitcoin',
23+
chainId: 'mainnet',
24+
},
25+
],
26+
)
27+
28+
export type BaseEndpointTypes = {
29+
Parameters: typeof inputParameters.definition
30+
Response: {
31+
Result: null
32+
Data: {
33+
result: PoRAddress[]
34+
}
35+
}
36+
Settings: typeof config.settings
37+
}
38+
39+
export const endpoint = new AdapterEndpoint({
40+
name: 'coinbaseBtcAddress',
41+
transport: coinbaseHttpTransport,
42+
inputParameters,
43+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { endpoint as address } from './address'
22
export { endpoint as solvBTC } from './solvBTC'
33
export { endpoint as bedrockBTC } from './bedrockBTC'
4+
export { endpoint as coinbaseBTC } from './coinbaseCBBTC'
45
export { endpoint as multichainAddress } from './multichainAddress'

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
22
import { PoRAdapter } from '@chainlink/external-adapter-framework/adapter/por'
33
import { config } from './config'
4-
import { address, solvBTC, bedrockBTC, multichainAddress } from './endpoint'
4+
import { address, solvBTC, bedrockBTC, coinbaseBTC, multichainAddress } from './endpoint'
55

66
export const adapter = new PoRAdapter({
77
defaultEndpoint: address.name,
88
name: 'POR_ADDRESS_LIST',
99
config,
10-
endpoints: [address, solvBTC, bedrockBTC, multichainAddress],
10+
endpoints: [address, solvBTC, bedrockBTC, coinbaseBTC, multichainAddress],
1111
rateLimiting: {
1212
tiers: {
1313
default: {
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { HttpTransport } from '@chainlink/external-adapter-framework/transports'
2+
import { TypeFromDefinition } from '@chainlink/external-adapter-framework/validation/input-params'
3+
import { BaseEndpointTypes } from '../endpoint/coinbaseCBBTC'
4+
5+
interface ResponseSchema {
6+
schema: string
7+
lastUpdatedAt: string
8+
reservesTotal: {
9+
amount: string
10+
currency: {
11+
name: string
12+
}
13+
network: {
14+
name: string
15+
}
16+
}
17+
reserveAddresses: {
18+
address: string
19+
balance: {
20+
amount: string
21+
currency: {
22+
name: string
23+
}
24+
network: {
25+
name: string
26+
}
27+
}
28+
}[]
29+
wrappedAssetsByNetwork: {
30+
amount: string
31+
currency: {
32+
name: string
33+
address: string
34+
}
35+
network: {
36+
name: string
37+
chainId: string
38+
}
39+
}[]
40+
wrappedAssetsTotal: {
41+
amount: string
42+
currency: {
43+
name: string
44+
}
45+
}
46+
}
47+
48+
export type HttpTransportTypes = BaseEndpointTypes & {
49+
Provider: {
50+
RequestBody: never
51+
ResponseBody: ResponseSchema
52+
}
53+
}
54+
55+
export const coinbaseHttpTransport = new HttpTransport<HttpTransportTypes>({
56+
prepareRequests: (params, config) => {
57+
return params.map((param) => {
58+
return {
59+
params: [param],
60+
request: {
61+
baseURL: config.COINBASE_CBBTC_API_ENDPOINT,
62+
},
63+
}
64+
})
65+
},
66+
67+
parseResponse: (params, response) => {
68+
if (!response.data) {
69+
return [
70+
{
71+
params: params[0],
72+
response: {
73+
errorMessage: `The data provider didn't return any data for coinbaseBTC`,
74+
statusCode: 502,
75+
},
76+
},
77+
]
78+
}
79+
80+
const addresses = getAddresses(params[0].network, params[0].chainId, response.data)
81+
82+
if (addresses.length == 0) {
83+
return [
84+
{
85+
params: params[0],
86+
response: {
87+
errorMessage: `The data provider didn't return any address for coinbaseBTC`,
88+
statusCode: 502,
89+
},
90+
},
91+
]
92+
}
93+
94+
return [
95+
{
96+
params: params[0],
97+
response: {
98+
result: null,
99+
data: {
100+
result: addresses,
101+
},
102+
},
103+
},
104+
]
105+
},
106+
})
107+
108+
const getAddresses = (
109+
network_name: TypeFromDefinition<BaseEndpointTypes['Parameters']>['network'],
110+
chain_id: TypeFromDefinition<BaseEndpointTypes['Parameters']>['chainId'],
111+
data: ResponseSchema,
112+
) => {
113+
return data.reserveAddresses
114+
.map((d) => ({
115+
address: d.address,
116+
network: network_name,
117+
chainId: chain_id,
118+
}))
119+
.sort()
120+
}

packages/sources/por-address-list/test/integration/__snapshots__/adapter.test.ts.snap

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,41 @@ exports[`execute apiAddress endpoint bedrock vault should return success 1`] = `
139139
}
140140
`;
141141

142+
exports[`execute apiAddress endpoint coinbase BTC should return success 1`] = `
143+
{
144+
"data": {
145+
"result": [
146+
{
147+
"address": "bc1qkqu7akp4lf3vmkde5l4ydp596wp8fm93m9yptd",
148+
"chainId": "mainnet",
149+
"network": "bitcoin",
150+
},
151+
{
152+
"address": "1xT8bWnZzS339nQLnrdqBW6yz8Nt5KjLC",
153+
"chainId": "mainnet",
154+
"network": "bitcoin",
155+
},
156+
{
157+
"address": "1FprAosJemf7TDvLGaTHbUWms3Z1uLUwJS",
158+
"chainId": "mainnet",
159+
"network": "bitcoin",
160+
},
161+
{
162+
"address": "1CgpdCJAkEQrzgqRh4C2EkyKsGCZxDFPEa",
163+
"chainId": "mainnet",
164+
"network": "bitcoin",
165+
},
166+
],
167+
},
168+
"result": null,
169+
"statusCode": 200,
170+
"timestamps": {
171+
"providerDataReceivedUnixMs": 978347471111,
172+
"providerDataRequestedUnixMs": 978347471111,
173+
},
174+
}
175+
`;
176+
142177
exports[`execute apiAddress endpoint solv should return success 1`] = `
143178
{
144179
"data": {

packages/sources/por-address-list/test/integration/adapter.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import {
44
} from '@chainlink/external-adapter-framework/util/testing-utils'
55
import * as nock from 'nock'
66
import { ethers } from 'ethers'
7-
import { mockBedRockResponseSuccess, mockSolvResponseSuccess } from './fixtures-api'
7+
import {
8+
mockBedRockResponseSuccess,
9+
mockCoinbaseResponseSuccess,
10+
mockSolvResponseSuccess,
11+
} from './fixtures-api'
812

913
const mockExpectedAddresses = [
1014
'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
@@ -57,6 +61,7 @@ describe('execute', () => {
5761
oldEnv = JSON.parse(JSON.stringify(process.env))
5862
process.env.RPC_URL = process.env.RPC_URL ?? 'http://localhost:8545'
5963
process.env.BEDROCK_UNIBTC_API_ENDPOINT = 'http://bedrock'
64+
process.env.COINBASE_CBBTC_API_ENDPOINT = 'http://coinbase'
6065
process.env.SOLVBTC_API_ENDPOINT = 'http://solv'
6166
process.env.BACKGROUND_EXECUTE_MS = '0'
6267
process.env.RATE_LIMIT_CAPACITY_SECOND = '500'
@@ -133,5 +138,17 @@ describe('execute', () => {
133138
expect(response.statusCode).toBe(200)
134139
expect(response.json()).toMatchSnapshot()
135140
})
141+
142+
it('coinbase BTC should return success', async () => {
143+
const data = {
144+
endpoint: 'coinbaseBtcAddress',
145+
network: 'bitcoin',
146+
chainId: 'mainnet',
147+
}
148+
mockCoinbaseResponseSuccess()
149+
const response = await testAdapter.request(data)
150+
expect(response.statusCode).toBe(200)
151+
expect(response.json()).toMatchSnapshot()
152+
})
136153
})
137154
})

0 commit comments

Comments
 (0)