Skip to content

Commit c242f89

Browse files
authored
view function Aptos (#3704)
1 parent 839728f commit c242f89

File tree

10 files changed

+203
-4
lines changed

10 files changed

+203
-4
lines changed

.changeset/chatty-sheep-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@chainlink/view-function-multi-chain-adapter': minor
3+
---
4+
5+
Aptos

packages/scripts/src/schema-flatten/lib.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function createChainlinkLabsResolver() {
124124

125125
const resolver: $RefParser.ResolverOptions = {
126126
order: 1,
127-
canRead: /^https:\/\/external-adapters\.chainlinklabs\.com$/i,
127+
canRead: /^https:\/\/external-adapters\.chainlinklabs\.com\//i,
128128
read: (file, callback) => {
129129
if (!callback) {
130130
console.error('[resolver] No callback found')

packages/sources/view-function-multi-chain/src/config/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { AdapterConfig } from '@chainlink/external-adapter-framework/config'
22

33
export const config = new AdapterConfig({
4+
APTOS_URL: {
5+
description: 'Aptos rest api url',
6+
type: 'string',
7+
required: false,
8+
default: '',
9+
},
10+
411
BACKGROUND_EXECUTE_MS: {
512
description:
613
'The amount of time the background execute should sleep before performing the next request',
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
2+
import { InputParameters } from '@chainlink/external-adapter-framework/validation'
3+
import { AdapterInputError } from '@chainlink/external-adapter-framework/validation/error'
4+
import { config } from '../config'
5+
import { aptosTransport } from '../transport/aptos'
6+
7+
export const inputParameters = new InputParameters({
8+
signature: {
9+
type: 'string',
10+
aliases: ['function'],
11+
required: true,
12+
description: 'Function signature. Format: {address}::{module name}::{function name}',
13+
},
14+
arguments: {
15+
array: true,
16+
description: 'Arguments of the function',
17+
type: 'string',
18+
},
19+
type: {
20+
array: true,
21+
description: 'Type arguments of the function',
22+
type: 'string',
23+
},
24+
index: {
25+
description: 'Which item in the function output array to return',
26+
type: 'number',
27+
default: 0,
28+
},
29+
})
30+
31+
export type BaseEndpointTypes = {
32+
Parameters: typeof inputParameters.definition
33+
Response: {
34+
Data: {
35+
result: string
36+
}
37+
Result: string
38+
}
39+
Settings: typeof config.settings
40+
}
41+
42+
export const endpoint = new AdapterEndpoint({
43+
name: 'aptos',
44+
transport: aptosTransport,
45+
inputParameters,
46+
customInputValidation: (_, adapterSettings): AdapterInputError | undefined => {
47+
if (!adapterSettings['APTOS_URL']) {
48+
throw new AdapterInputError({
49+
statusCode: 400,
50+
message: `Error: missing environment variable APTOS_URL`,
51+
})
52+
}
53+
return
54+
},
55+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { endpoint as functionEndpoint } from './function'
2+
export { endpoint as aptosEndpoint } from './aptos'
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
import { expose, ServerInstance } from '@chainlink/external-adapter-framework'
22
import { Adapter } from '@chainlink/external-adapter-framework/adapter'
33
import { config } from './config'
4-
import { functionEndpoint } from './endpoint'
4+
import { functionEndpoint, aptosEndpoint } from './endpoint'
55

66
export const adapter = new Adapter({
77
defaultEndpoint: functionEndpoint.name,
88
name: 'VIEW_FUNCTION_MULTI_CHAIN',
99
config,
10-
endpoints: [functionEndpoint],
10+
endpoints: [functionEndpoint, aptosEndpoint],
11+
rateLimiting: {
12+
tiers: {
13+
default: {
14+
rateLimit1s: 1,
15+
note: 'Reasonable limits',
16+
},
17+
},
18+
},
1119
})
1220

1321
export const server = (): Promise<ServerInstance | undefined> => expose(adapter)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { HttpTransport } from '@chainlink/external-adapter-framework/transports'
2+
import { BaseEndpointTypes } from '../endpoint/aptos'
3+
4+
export type HttpTransportTypes = BaseEndpointTypes & {
5+
Provider: {
6+
RequestBody: { function: string; type_arguments: string[]; arguments: string[] }
7+
ResponseBody:
8+
| any[]
9+
| {
10+
message: string
11+
error_code: string
12+
vm_error_code: number
13+
}
14+
}
15+
}
16+
export const aptosTransport = new HttpTransport<HttpTransportTypes>({
17+
prepareRequests: (params, config) => {
18+
return params.map((param) => {
19+
return {
20+
params: [param],
21+
request: {
22+
baseURL: config.APTOS_URL,
23+
url: '/view',
24+
method: 'POST',
25+
headers: {
26+
'Content-Type': 'application/json',
27+
},
28+
data: {
29+
function: param.signature,
30+
type_arguments: param.type,
31+
arguments: param.arguments,
32+
},
33+
},
34+
}
35+
})
36+
},
37+
parseResponse: (params, response) => {
38+
if (response.data instanceof Array) {
39+
if (params[0].index >= response.data.length) {
40+
return [
41+
{
42+
params: params[0],
43+
response: {
44+
errorMessage: `index ${
45+
params[0].index
46+
} is more than result array length ${JSON.stringify(response.data)}`,
47+
statusCode: 502,
48+
},
49+
},
50+
]
51+
}
52+
return response.data.map((elem, i) => ({
53+
params: {
54+
...params[0],
55+
index: i,
56+
},
57+
response: {
58+
result: elem,
59+
data: {
60+
result: elem,
61+
},
62+
},
63+
}))
64+
} else {
65+
return [
66+
{
67+
params: params[0],
68+
response: {
69+
errorMessage: JSON.stringify(response.data),
70+
statusCode: 502,
71+
},
72+
},
73+
]
74+
}
75+
},
76+
})

packages/sources/view-function-multi-chain/test/integration/__snapshots__/adapter.test.ts.snap

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`execute aptos endpoint should return success 1`] = `
4+
{
5+
"data": {
6+
"result": 1,
7+
},
8+
"result": 1,
9+
"statusCode": 200,
10+
"timestamps": {
11+
"providerDataReceivedUnixMs": 978347471111,
12+
"providerDataRequestedUnixMs": 978347471111,
13+
},
14+
}
15+
`;
16+
317
exports[`execute function endpoint should return error for invalid input 1`] = `
418
{
5-
"errorMessage": "no matching function (argument="key", value="symbol() view returns (string)", code=INVALID_ARGUMENT, version=6.13.4)",
19+
"errorMessage": "no matching function (argument="key", value="symbol() view returns (string)", code=INVALID_ARGUMENT, version=6.13.5)",
620
"statusCode": 502,
721
"timestamps": {
822
"providerDataReceivedUnixMs": 0,

packages/sources/view-function-multi-chain/test/integration/adapter.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as nock from 'nock'
66
import {
77
mockETHGoerliContractCallResponseSuccess,
88
mockETHMainnetContractCallResponseSuccess,
9+
mockAptosSuccess,
910
} from './fixtures'
1011
import * as process from 'process'
1112

@@ -23,10 +24,12 @@ describe('execute', () => {
2324
process.env.ETHEREUM_GOERLI_RPC_URL ?? 'http://localhost:8554'
2425
process.env.ETHEREUM_GOERLI_CHAIN_ID = process.env.ETHEREUM_GOERLI_CHAIN_ID ?? '5'
2526
process.env.BACKGROUND_EXECUTE_MS = '0'
27+
process.env.APTOS_URL = process.env.APTOS_URL ?? 'http://fake-aptos'
2628
const mockDate = new Date('2001-01-01T11:11:11.111Z')
2729
spy = jest.spyOn(Date, 'now').mockReturnValue(mockDate.getTime())
2830

2931
const adapter = (await import('./../../src')).adapter
32+
adapter.rateLimiting = undefined
3033
testAdapter = await TestAdapter.startWithMockedCache(adapter, {
3134
testAdapter: {} as TestAdapter<never>,
3235
})
@@ -110,4 +113,16 @@ describe('execute', () => {
110113
expect(response.json()).toMatchSnapshot()
111114
})
112115
})
116+
117+
describe('aptos endpoint', () => {
118+
it('should return success', async () => {
119+
mockAptosSuccess()
120+
const response = await testAdapter.request({
121+
endpoint: 'aptos',
122+
signature: '0x1::chain_id::get',
123+
})
124+
expect(response.statusCode).toBe(200)
125+
expect(response.json()).toMatchSnapshot()
126+
})
127+
})
113128
})

packages/sources/view-function-multi-chain/test/integration/fixtures.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,21 @@ export const mockETHGoerliContractCallResponseSuccess = (): nock.Scope =>
118118
],
119119
)
120120
.persist()
121+
122+
export const mockAptosSuccess = (): nock.Scope =>
123+
nock('http://fake-aptos', {
124+
encodedQueryParams: true,
125+
})
126+
.persist()
127+
.post('/view')
128+
.reply(200, () => [1], [
129+
'Content-Type',
130+
'application/json',
131+
'Connection',
132+
'close',
133+
'Vary',
134+
'Accept-Encoding',
135+
'Vary',
136+
'Origin',
137+
])
138+
.persist()

0 commit comments

Comments
 (0)