-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Multi Chain PoR Address List EA (#3561)
- Loading branch information
Showing
13 changed files
with
405 additions
and
10 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@chainlink/por-address-list-adapter': minor | ||
--- | ||
|
||
Add multichainAddress endpoint |
32 changes: 32 additions & 0 deletions
32
packages/sources/por-address-list/src/config/MultiEVMPoRAddressList.json
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,32 @@ | ||
[ | ||
{ | ||
"inputs": [ | ||
{ "internalType": "uint256", "name": "startIndex", "type": "uint256" }, | ||
{ "internalType": "uint256", "name": "endIndex", "type": "uint256" } | ||
], | ||
"name": "getPoRAddressList", | ||
"outputs": [ | ||
{ | ||
"components": [ | ||
{ "internalType": "string", "name": "chain", "type": "string" }, | ||
{ "internalType": "uint256", "name": "chainId", "type": "uint256" }, | ||
{ "internalType": "string", "name": "tokenSymbol", "type": "string" }, | ||
{ "internalType": "address", "name": "tokenAddress", "type": "address" }, | ||
{ "internalType": "address", "name": "vaultAddress", "type": "address" } | ||
], | ||
"internalType": "struct IMultiEVMPoRAddressList.PoRInfo[]", | ||
"name": "", | ||
"type": "tuple[]" | ||
} | ||
], | ||
"stateMutability": "view", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "getPoRAddressListLength", | ||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], | ||
"stateMutability": "view", | ||
"type": "function" | ||
} | ||
] |
32 changes: 32 additions & 0 deletions
32
packages/sources/por-address-list/src/config/PoRAddressListMulti.json
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,32 @@ | ||
[ | ||
{ | ||
"inputs": [ | ||
{ "internalType": "uint256", "name": "startIndex_", "type": "uint256" }, | ||
{ "internalType": "uint256", "name": "endIndex_", "type": "uint256" } | ||
], | ||
"name": "getPoRAddressList", | ||
"outputs": [ | ||
{ | ||
"components": [ | ||
{ "internalType": "string", "name": "tokenSymbol", "type": "string" }, | ||
{ "internalType": "string", "name": "chain", "type": "string" }, | ||
{ "internalType": "uint64", "name": "chainId", "type": "uint64" }, | ||
{ "internalType": "address", "name": "tokenAddress", "type": "address" }, | ||
{ "internalType": "address", "name": "vaultAddress", "type": "address" } | ||
], | ||
"internalType": "struct IPoRAddressListMulti.TokenVaultInfo[]", | ||
"name": "tokenVaultInfos_", | ||
"type": "tuple[]" | ||
} | ||
], | ||
"stateMutability": "view", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "getPoRAddressListLength", | ||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], | ||
"stateMutability": "view", | ||
"type": "function" | ||
} | ||
] |
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { endpoint as address } from './address' | ||
export { endpoint as solvBTC } from './solvBTC' | ||
export { endpoint as bedrockBTC } from './bedrockBTC' | ||
export { endpoint as multichainAddress } from './multichainAddress' |
55 changes: 55 additions & 0 deletions
55
packages/sources/por-address-list/src/endpoint/multichainAddress.ts
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,55 @@ | ||
import { | ||
PoRTokenAddressEndpoint, | ||
PoRTokenAddressResponse, | ||
} from '@chainlink/external-adapter-framework/adapter/por' | ||
import { InputParameters } from '@chainlink/external-adapter-framework/validation' | ||
import { config } from '../config' | ||
import { addressTransport } from '../transport/multichainAddress' | ||
|
||
export const inputParameters = new InputParameters( | ||
{ | ||
contractAddress: { | ||
description: 'The contract address holding the custodial addresses', | ||
type: 'string', | ||
required: true, | ||
}, | ||
contractAddressNetwork: { | ||
description: | ||
'The network of the contract, used to match {NETWORK}_RPC_URL and {NETWORK}_RPC_CHAIN_ID in env var', | ||
type: 'string', | ||
required: true, | ||
}, | ||
confirmations: { | ||
description: 'The number of confirmations to query data from', | ||
type: 'number', | ||
default: 0, | ||
}, | ||
batchSize: { | ||
description: 'The number of addresses to fetch from the contract at a time', | ||
type: 'number', | ||
default: 10, | ||
}, | ||
}, | ||
[ | ||
{ | ||
contractAddress: '0xb7C0817Dd23DE89E4204502dd2C2EF7F57d3A3B8', | ||
contractAddressNetwork: 'BINANCE', | ||
confirmations: 0, | ||
batchSize: 10, | ||
}, | ||
], | ||
) | ||
|
||
type ResponseSchema = PoRTokenAddressResponse | ||
|
||
export type BaseEndpointTypes = { | ||
Parameters: typeof inputParameters.definition | ||
Response: ResponseSchema | ||
Settings: typeof config.settings | ||
} | ||
|
||
export const endpoint = new PoRTokenAddressEndpoint({ | ||
name: 'multichainAddress', | ||
transport: addressTransport, | ||
inputParameters, | ||
}) |
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 |
---|---|---|
@@ -1,13 +1,13 @@ | ||
import { expose, ServerInstance } from '@chainlink/external-adapter-framework' | ||
import { PoRAdapter } from '@chainlink/external-adapter-framework/adapter/por' | ||
import { config } from './config' | ||
import { address, solvBTC, bedrockBTC } from './endpoint' | ||
import { address, solvBTC, bedrockBTC, multichainAddress } from './endpoint' | ||
|
||
export const adapter = new PoRAdapter({ | ||
defaultEndpoint: address.name, | ||
name: 'POR_ADDRESS_LIST', | ||
config, | ||
endpoints: [address, solvBTC, bedrockBTC], | ||
endpoints: [address, solvBTC, bedrockBTC, multichainAddress], | ||
}) | ||
|
||
export const server = (): Promise<ServerInstance | undefined> => expose(adapter) |
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
125 changes: 125 additions & 0 deletions
125
packages/sources/por-address-list/src/transport/multichainAddress.ts
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,125 @@ | ||
import { SubscriptionTransport } from '@chainlink/external-adapter-framework/transports/abstract/subscription' | ||
import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' | ||
import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' | ||
import { AdapterResponse, sleep } from '@chainlink/external-adapter-framework/util' | ||
import ABI from '../config/PoRAddressListMulti.json' | ||
import PolygonABI from '../config/MultiEVMPoRAddressList.json' | ||
import { BaseEndpointTypes, inputParameters } from '../endpoint/multichainAddress' | ||
import { ethers } from 'ethers' | ||
import { fetchAddressList, addProvider, getProvider } from './utils' | ||
|
||
export type AddressTransportTypes = BaseEndpointTypes | ||
|
||
type RequestParams = typeof inputParameters.validated | ||
|
||
interface ResponseSchema { | ||
tokenSymbol: string | ||
chain: string | ||
chainId: bigint | ||
tokenAddress: string | ||
vaultAddress: string | ||
} | ||
|
||
export class AddressTransport extends SubscriptionTransport<AddressTransportTypes> { | ||
providersMap: Record<string, ethers.providers.JsonRpcProvider> = {} | ||
settings!: AddressTransportTypes['Settings'] | ||
|
||
async initialize( | ||
dependencies: TransportDependencies<AddressTransportTypes>, | ||
adapterSettings: AddressTransportTypes['Settings'], | ||
endpointName: string, | ||
transportName: string, | ||
): Promise<void> { | ||
await super.initialize(dependencies, adapterSettings, endpointName, transportName) | ||
this.settings = adapterSettings | ||
} | ||
|
||
async backgroundHandler( | ||
context: EndpointContext<AddressTransportTypes>, | ||
entries: RequestParams[], | ||
) { | ||
await Promise.all(entries.map(async (param) => this.handleRequest(param))) | ||
await sleep(context.adapterSettings.BACKGROUND_EXECUTE_MS) | ||
} | ||
|
||
async handleRequest(param: RequestParams) { | ||
let response: AdapterResponse<BaseEndpointTypes['Response']> | ||
try { | ||
response = await this._handleRequest(param) | ||
} catch (e) { | ||
const errorMessage = e instanceof Error ? e.message : 'Unknown error occurred' | ||
response = { | ||
statusCode: 502, | ||
errorMessage, | ||
timestamps: { | ||
providerDataRequestedUnixMs: 0, | ||
providerDataReceivedUnixMs: 0, | ||
providerIndicatedTimeUnixMs: undefined, | ||
}, | ||
} | ||
} | ||
await this.responseCache.write(this.name, [{ params: param, response }]) | ||
} | ||
|
||
async _handleRequest( | ||
param: RequestParams, | ||
): Promise<AdapterResponse<AddressTransportTypes['Response']>> { | ||
const { confirmations, contractAddress, contractAddressNetwork, batchSize } = param | ||
|
||
this.providersMap = addProvider(contractAddressNetwork, this.providersMap) | ||
const provider = getProvider(contractAddressNetwork, this.providersMap) | ||
|
||
const addressManager = new ethers.Contract( | ||
contractAddress, | ||
contractAddressNetwork == 'POLYGON' ? PolygonABI : ABI, | ||
provider, | ||
) | ||
const latestBlockNum = await provider.getBlockNumber() | ||
|
||
const providerDataRequestedUnixMs = Date.now() | ||
const addressList = await fetchAddressList<ResponseSchema>( | ||
addressManager, | ||
latestBlockNum, | ||
confirmations, | ||
batchSize, | ||
this.settings.GROUP_SIZE, | ||
) | ||
|
||
const addressByChain = Map.groupBy( | ||
addressList, | ||
(address) => address.chainId.toString() + address.tokenAddress, | ||
) | ||
|
||
const response = Array.from( | ||
new Map( | ||
Array.from(addressByChain, ([k, v]) => [ | ||
k, | ||
{ | ||
chainId: v[0].chainId.toString(), | ||
contractAddress: v[0].tokenAddress, | ||
wallets: v.map((v) => v.vaultAddress), | ||
}, | ||
]), | ||
).values(), | ||
).sort() | ||
|
||
return { | ||
data: { | ||
result: response, | ||
}, | ||
statusCode: 200, | ||
result: null, | ||
timestamps: { | ||
providerDataRequestedUnixMs, | ||
providerDataReceivedUnixMs: Date.now(), | ||
providerIndicatedTimeUnixMs: undefined, | ||
}, | ||
} | ||
} | ||
|
||
getSubscriptionTtlFromConfig(adapterSettings: BaseEndpointTypes['Settings']): number { | ||
return adapterSettings.WARMUP_SUBSCRIPTION_TTL | ||
} | ||
} | ||
|
||
export const addressTransport = new AddressTransport() |
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
31 changes: 31 additions & 0 deletions
31
...s/sources/por-address-list/test/integration/__snapshots__/adapter-multichain.test.ts.snap
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,31 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`execute multichainAddress endpoint should return success 1`] = ` | ||
{ | ||
"data": { | ||
"result": [ | ||
{ | ||
"chainId": "56", | ||
"contractAddress": "token1", | ||
"wallets": [ | ||
"vault1", | ||
"vault2", | ||
], | ||
}, | ||
{ | ||
"chainId": "223", | ||
"contractAddress": "token3", | ||
"wallets": [ | ||
"vault3", | ||
], | ||
}, | ||
], | ||
}, | ||
"result": null, | ||
"statusCode": 200, | ||
"timestamps": { | ||
"providerDataReceivedUnixMs": 978347471111, | ||
"providerDataRequestedUnixMs": 978347471111, | ||
}, | ||
} | ||
`; |
Oops, something went wrong.