-
Notifications
You must be signed in to change notification settings - Fork 303
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add Agoric adapter * fix: use agoric_oracle_query_id * fix: make more explicit * test: remove agoric/test * fix: another attempt to plumb through the 'Task Run Data' * fix: use the promise-based API * fix: make request_id numeric * fix: cast payment from number to string * fix: properly export the Agoric async adapter and string queryId * refactor: separate concerns and add tests * fix: more robust adapter; send errors to the oracleServer * feat!: surface errors from the oracle backend * fix: match with actual POST reply from the ag-solo * fix: use AdapterErrors to surface errors to the node operator * test: add integration test * fix: use Requester instead of axios * chore: rename package to @chainlink/agoric * ci: add "agoric" to adapters.json * refactor: clarify implementation according to review comments * refactor: use the adapter-test-helpers * ci: fix the Agoric build process * fix: address review comments * refactor: standardize code based on example adapter * fix: import makeConfig * fix: correct the default agoric adapter parameters * chore: remove dependency on bn.js
- Loading branch information
1 parent
1a39885
commit 04d9264
Showing
12 changed files
with
402 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
...require('../.eslintrc.ts.js'), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Chainlink External Adapter for Agoric | ||
|
||
This adapter posts a result to the [Agoric blockchain](https://agoric.com). See | ||
the [Agoric Chainlink Oracle | ||
integration](https://github.com/Agoric/dapp-oracle/tree/master/chainlink-agoric) | ||
for details on how to use it with your Chainlink node. | ||
|
||
|
||
| Required? | Name | Description | Options | Defaults to | | ||
| :-------: | :------: | :-----------------: | :--------------------------: | :---------: | | ||
| | endpoint | The endpoint to use | [agoric](#Agoric-endpoint) | agoric | | ||
|
||
--- | ||
|
||
## Agoric endpoint | ||
|
||
This is the endpoint exposed by your local `ag-solo` after installing the | ||
[Agoric Chainlink Oracle | ||
integration](https://github.com/Agoric/dapp-oracle/tree/master/chainlink-agoric). | ||
|
||
The default is http://localhost:8000/api/oracle | ||
|
||
### Input Params | ||
|
||
| Required? | Name | Description | Options | Defaults to | | ||
| :-------: | :------------------------: | :--------------------------------------: | :-----------------: | :---------: | | ||
| ✅ | `request_id` | The Agoric oracle queryId | string | request_id from Agoric External Initiator | | ||
| | `payment` | How much $LINK the Chainlink node would like to collect as a fee | number as a string | the whole fee the user offered | | ||
| ✅ | `result` | The result to return to the Agoric oracle contract | string | | | ||
|
||
## Output | ||
|
||
```json | ||
{ | ||
"jobRunID": "278c97ffadb54a5bbb93cfec5f7b5503", | ||
"data": { "result": "..." }, | ||
"statusCode": 200 | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"name": "@chainlink/agoric-adapter", | ||
"version": "0.0.1", | ||
"description": "Chainlink adapter to post to the Agoric blockchain", | ||
"keywords": [ | ||
"Chainlink", | ||
"LINK", | ||
"blockchain", | ||
"oracle" | ||
], | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"repository": { | ||
"url": "https://github.com/smartcontractkit/external-adapters-js", | ||
"type": "git" | ||
}, | ||
"license": "MIT", | ||
"scripts": { | ||
"prepublishOnly": "yarn build && yarn test:unit", | ||
"setup": "yarn build", | ||
"build": "tsc -b", | ||
"lint": "eslint --ignore-path ../.eslintignore . --ext .js,.jsx,.ts,.tsx", | ||
"lint:fix": "eslint --ignore-path ../.eslintignore . --ext .js,.jsx,.ts,.tsx --fix", | ||
"test": "mocha --exit --timeout 3000 -r ts-node/register 'test/**/*.test.ts'", | ||
"test:unit": "mocha --exit --grep @integration --invert -r ts-node/register 'test/**/*.test.ts'", | ||
"test:integration": "mocha --exit --timeout 3000 --grep @integration -r ts-node/register 'test/**/*.test.ts'", | ||
"server": "node -e 'require(\"./index.js\").server()'", | ||
"server:dist": "node -e 'require(\"./dist/index.js\").server()'", | ||
"start": "yarn server:dist" | ||
}, | ||
"devDependencies": { | ||
"@types/chai": "^4.2.11", | ||
"@types/express": "^4.17.6", | ||
"@types/mocha": "^7.0.2", | ||
"@types/node": "^14.0.13", | ||
"@typescript-eslint/eslint-plugin": "^3.9.0", | ||
"@typescript-eslint/parser": "^3.9.0", | ||
"ts-node": "^8.10.2", | ||
"typescript": "^3.9.7" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { BigNumber } from 'ethers' | ||
|
||
import { Config, ExecuteWithConfig, ExecuteFactory } from '@chainlink/types' | ||
import { Requester, Validator, AdapterError } from '@chainlink/external-adapter' | ||
|
||
import { makeConfig } from './config' | ||
|
||
// We're on localhost, so retries just confuse the oracle state. | ||
const NUM_RETRIES = 1 | ||
|
||
export interface Action { | ||
type: string | ||
data: unknown | ||
} | ||
|
||
const inputParams = { | ||
request_id: ['request_id'], | ||
result: ['result'], | ||
payment: ['payment'], | ||
} | ||
|
||
// FIXME: Ideally, these would be the same. | ||
const LINK_UNIT = BigNumber.from(10).pow(BigNumber.from(18)) | ||
const LINK_AGORIC_UNIT = BigNumber.from(10).pow(BigNumber.from(6)) | ||
|
||
// Convert the payment in $LINK into Agoric's pegged $LINK token. | ||
export const getRequiredFee = (value: string | number): number => { | ||
const paymentCL = BigNumber.from(value) | ||
const paymentAgoricLink = paymentCL.mul(LINK_AGORIC_UNIT).div(LINK_UNIT) | ||
return paymentAgoricLink.toNumber() | ||
} | ||
|
||
export interface PostReply { | ||
ok: boolean | ||
res?: unknown | ||
rej?: unknown | ||
} | ||
|
||
const executeImpl: ExecuteWithConfig<Config> = async (request, config) => { | ||
const validator = new Validator(request, inputParams) | ||
if (validator.error) { | ||
throw validator.error | ||
} | ||
|
||
Requester.logConfig(config) | ||
|
||
const jobRunID = validator.validated.id | ||
const { request_id: queryId, result, payment } = validator.validated.data | ||
const requiredFee = getRequiredFee(payment) | ||
|
||
const obj = { | ||
type: 'oracleServer/reply', | ||
data: { queryId, reply: result, requiredFee }, | ||
} | ||
|
||
const response = await Requester.request( | ||
{ | ||
...config.api, | ||
method: 'POST', | ||
data: obj, | ||
}, | ||
undefined, | ||
NUM_RETRIES, | ||
) | ||
|
||
const pr = response.data as PostReply | ||
if (!pr.ok) { | ||
throw Error(`${obj.type} response failed: ${pr.rej}`) | ||
} | ||
|
||
return Requester.success(jobRunID, { | ||
data: { result }, | ||
result, | ||
status: 200, | ||
}) | ||
} | ||
|
||
const tryExecuteLogError = ( | ||
execute: ExecuteWithConfig<Config>, | ||
): ExecuteWithConfig<Config> => async (request, config) => { | ||
try { | ||
return await execute(request, config) | ||
} catch (e) { | ||
const queryId = request.data?.request_id | ||
const rest = { queryId } | ||
|
||
await Requester.request( | ||
{ | ||
...config.api, | ||
method: 'POST', | ||
data: { | ||
type: 'oracleServer/error', | ||
data: { error: `${(e && e.message) || e}`, ...(queryId && rest) }, | ||
}, | ||
}, | ||
undefined, | ||
NUM_RETRIES, | ||
).catch((e2: Error) => console.error(`Cannot reflect error to caller:`, e2)) | ||
|
||
// See https://github.com/smartcontractkit/external-adapters-js/issues/204 | ||
// for discussion of why this code is necessary. | ||
if (e instanceof AdapterError) { | ||
throw e | ||
} | ||
throw new AdapterError({ | ||
jobRunID: request.id, | ||
statusCode: 500, | ||
message: `${(e && e.message) || e}`, | ||
cause: e, | ||
}) | ||
} | ||
} | ||
|
||
export const execute = tryExecuteLogError(executeImpl) | ||
export const makeExecute: ExecuteFactory<Config> = (config) => { | ||
return async (request) => execute(request, config || makeConfig()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Requester } from '@chainlink/external-adapter' | ||
import { Config } from '@chainlink/types' | ||
import { util } from '@chainlink/ea-bootstrap' | ||
|
||
export const DEFAULT_API_ENDPOINT = 'http://localhost:8000/api/oracle' | ||
|
||
// This environment variable is needed for the Hack the Orb oracle | ||
// instructions to remain correct. | ||
const LEGACY_API_ENDPOINT_ENV = 'AG_SOLO_ORACLE_URL' | ||
|
||
export const makeConfig = (prefix?: string): Config => { | ||
const config = Requester.getDefaultConfig(prefix) | ||
config.api.baseURL = | ||
config.api.baseURL || util.getEnv(LEGACY_API_ENDPOINT_ENV) || DEFAULT_API_ENDPOINT | ||
config.apiKey = config.apiKey || 'not required' | ||
return config | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { expose } from '@chainlink/ea-bootstrap' | ||
import { makeExecute } from './adapter' | ||
import { makeConfig } from './config' | ||
|
||
const NAME = 'Agoric' | ||
|
||
export = { NAME, makeExecute, makeConfig, ...expose(makeExecute()) } |
Oops, something went wrong.