Skip to content

Commit

Permalink
Proof of Reserves Aggregator (#3563)
Browse files Browse the repository at this point in the history
* Proof of Reserves Aggregator

* Add timestamps

* Fix multichainAddress input convention
  • Loading branch information
mxiao-cll authored Nov 18, 2024
1 parent 78cca56 commit 0b81fee
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-vans-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/proof-of-reserves-adapter': minor
---

Add multiReserves endpoint
5 changes: 5 additions & 0 deletions .changeset/large-ghosts-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/por-address-list-adapter': patch
---

Fix input convension
6 changes: 4 additions & 2 deletions packages/composites/proof-of-reserves/src/endpoint/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as reserves from './reserves'
import type { TInputParameters as SingleTInputParameters } from './reserves'
import type { TInputParameters as MultiTInputParameters } from './multiReserves'

export type TInputParameters = reserves.TInputParameters
export type TInputParameters = SingleTInputParameters | MultiTInputParameters

export * as reserves from './reserves'
export * as multiReserves from './multiReserves'
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { ExecuteWithConfig, InputParameters } from '@chainlink/ea-bootstrap'
import type { TInputParameters as SingleTInputParameters } from './reserves'
import { execute as singleExecute } from './reserves'
import { Validator } from '@chainlink/ea-bootstrap'
import { Config } from '../config'
import { AdapterError } from '@chainlink/ea-bootstrap'

export const supportedEndpoints = ['multiReserves']

export type TInputParameters = {
input: SingleTInputParameters[]
}

const inputParameters: InputParameters<TInputParameters> = {
input: {
required: true,
type: 'array',
description: 'An array of PoR request, each request is a request to the reserves endpoint',
},
}

export const execute: ExecuteWithConfig<Config> = async (input, context, config) => {
const providerDataRequestedUnixMs = Date.now()

const validator = new Validator(input, inputParameters)
const jobRunID = validator.validated.id

const results = await Promise.all(
validator.validated.data.input.map((input) =>
singleExecute(
{
id: jobRunID,
data: input,
},
context,
config,
),
),
)

const result = results
.map((result) => {
if (result.statusCode != 200 || !result.result) {
throw new AdapterError({
...result,
})
} else {
return scale(BigInt(result.result.toString()), result.data.decimals?.toString())
}
})
.reduce((s, e) => s + e)
.toString()

return {
jobRunID,
result: result,
statusCode: 200,
data: {
result: result,
statusCode: 200,
decimals: 18,
timestamps: {
providerDataRequestedUnixMs,
providerDataReceivedUnixMs: Date.now(),
},
},
}
}

const scale = (value: bigint, decimal?: string) => {
if (decimal) {
// Scale to 18 decimals
return value * 10n ** (18n - BigInt(decimal))
} else {
return value
}
}
1 change: 1 addition & 0 deletions packages/composites/proof-of-reserves/src/utils/reduce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const returnParsedUnits = (jobRunID: string, result: string, units: number) => {
data: {
result: convertedResult,
statusCode: 200,
decimals: units,
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`execute Bitcoin list protocol should return success 1`] = `
{
"data": {
"decimals": 8,
"result": "75100045155",
"statusCode": 200,
},
Expand All @@ -27,6 +28,7 @@ exports[`execute Ethereum list protocol should return success 1`] = `
exports[`execute Filecoin Gemini protocol should return success 1`] = `
{
"data": {
"decimals": 0,
"result": "127530375584000000000000",
"statusCode": 200,
},
Expand All @@ -38,10 +40,28 @@ exports[`execute Filecoin Gemini protocol should return success 1`] = `
exports[`execute Filecoin list protocol w/ miner format address should return success 1`] = `
{
"data": {
"decimals": 0,
"result": "127530375584000000000000",
"statusCode": 200,
},
"result": "127530375584000000000000",
"statusCode": 200,
}
`;

exports[`execute multiReserves endpoint should return success 1`] = `
{
"data": {
"decimals": 18,
"result": "751221097708354962165",
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 1641035471111,
"providerDataRequestedUnixMs": 1641035471111,
},
},
"jobRunID": "1",
"result": "751221097708354962165",
"statusCode": 200,
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ describe('execute', () => {

setupExternalAdapterTest(envVariables, context)

let spy: jest.SpyInstance
beforeAll(async () => {
const mockDate = new Date('2022-01-01T11:11:11.111Z')
spy = jest.spyOn(Date, 'now').mockReturnValue(mockDate.getTime())
})

afterAll((done) => {
spy.mockRestore()
done()
})

describe('Bitcoin list protocol', () => {
const data: AdapterRequest = {
id: '1',
Expand Down Expand Up @@ -101,7 +112,7 @@ describe('execute', () => {
.set('Accept', '*/*')
.set('Content-Type', 'application/json')
.expect('Content-Type', /json/)
// .expect(200)
.expect(200)
expect(response.body).toMatchSnapshot()
})
})
Expand All @@ -119,14 +130,63 @@ describe('execute', () => {
}

it('should return success', async () => {
//mockLotusSuccess()
mockLotusSuccess()
const response = await (context.req as SuperTest<Test>)
.post('/')
.send(data)
.set('Accept', '*/*')
.set('Content-Type', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
expect(response.body).toMatchSnapshot()
})
})

describe('multiReserves endpoint', () => {
it('should return success', async () => {
const data: AdapterRequest = {
id: '1',
data: {
endpoint: 'multiReserves',
input: [
{
protocol: 'list',
indexer: 'por_indexer',
addresses: [
{
address: '39e7mxbeNmRRnjfy1qkphv1TiMcztZ8VuE',
chainId: 'mainnet',
network: 'bitcoin',
},
{
address: '35ULMyVnFoYaPaMxwHTRmaGdABpAThM4QR',
chainId: 'mainnet',
network: 'bitcoin',
},
],
},
{
indexer: 'eth_balance',
protocol: 'list',
addresses: [
'0x8288C280F35FB8809305906C79BD075962079DD8',
'0x81910675DbaF69deE0fD77570BFD07f8E436386A',
],
confirmations: 5,
},
],
},
}
mockPoRindexerSuccess()
mockEthBalanceSuccess()

const response = await (context.req as SuperTest<Test>)
.post('/')
.send(data)
.set('Accept', '*/*')
.set('Content-Type', 'application/json')
.expect('Content-Type', /json/)
// .expect(200)
.expect(200)
expect(response.body).toMatchSnapshot()
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class AddressTransport extends SubscriptionTransport<AddressTransportType

const addressManager = new ethers.Contract(
contractAddress,
contractAddressNetwork == 'POLYGON' ? PolygonABI : ABI,
contractAddressNetwork.toUpperCase() == 'POLYGON' ? PolygonABI : ABI,
provider,
)
const latestBlockNum = await provider.getBlockNumber()
Expand Down

0 comments on commit 0b81fee

Please sign in to comment.