@gibs/bridge-indexer 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +62 -0
- package/dist/bridge-status.d.ts +58 -0
- package/dist/bridge-status.js +23 -0
- package/dist/endpoint.d.ts +49 -0
- package/dist/endpoint.js +59 -0
- package/dist/graphql.d.ts +2537 -0
- package/dist/graphql.js +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +23 -0
- package/dist/live-status.d.ts +18 -0
- package/dist/live-status.js +178 -0
- package/dist/transfers.d.ts +147 -0
- package/dist/transfers.js +711 -0
- package/package.json +104 -0
- package/schema.graphql +2047 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gibs Finance
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @gibs/bridge-indexer
|
|
2
|
+
|
|
3
|
+
Reads a Gibs Finance bridge indexer. It gives you the transfer archive, delivery receipts, and live crossing status. It only reads. It never signs or broadcasts.
|
|
4
|
+
|
|
5
|
+
## Endpoint
|
|
6
|
+
|
|
7
|
+
The package reads `https://next-indexer.gibs.finance` by default. This is the owner's choice "for now". The next indexer follows the current schema.
|
|
8
|
+
|
|
9
|
+
Importing the package has no side effects. The package creates its GraphQL client on first use.
|
|
10
|
+
|
|
11
|
+
To read another indexer, call `setIndexerEndpoint` before the first query:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { setIndexerEndpoint, indexerEndpoint, DEFAULT_INDEXER_ENDPOINT } from '@gibs/bridge-indexer'
|
|
15
|
+
|
|
16
|
+
setIndexerEndpoint('http://localhost:42069/graphql')
|
|
17
|
+
indexerEndpoint() // the address now in force
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The indexer serves GraphQL at `/` and at `/graphql`. It serves `GET /version` with the indexer package version, the Ponder schema name, and the git commit when the deploy sets `GIT_SHA`. The indexer no longer serves raw SQL.
|
|
21
|
+
|
|
22
|
+
Production `https://indexer.gibs.finance` may lag the schema in this package. If a query fails there with an unknown field, point the package at the next indexer.
|
|
23
|
+
|
|
24
|
+
## Known defects in the production data
|
|
25
|
+
|
|
26
|
+
A batched re-index will fix these. Until it runs, work around them.
|
|
27
|
+
|
|
28
|
+
- Five relations are always `null`. Do not read them:
|
|
29
|
+
- `AMBBridge.validatorContract`
|
|
30
|
+
- `Omnibridge.ambBridge`
|
|
31
|
+
- `Omnibridge.validatorContract`
|
|
32
|
+
- `UserRequest.destinationAMBBridge`
|
|
33
|
+
- `UserRequest.destinationOmnibridge`
|
|
34
|
+
- The joins between a request and its `Completion` or `Delivery` work in one direction only. Query `Completion` or `Delivery` by `messageHash` instead of expecting the join on the request.
|
|
35
|
+
- A message for a native pathway records the ERC-20 omnibridge, not the native one.
|
|
36
|
+
- Read `delivered` (a boolean on the request). Do not read `delivery`. The `delivery` relation can be `null` for a request that landed.
|
|
37
|
+
- Hex filters are lowercase. A checksummed address in a `where` clause matches nothing. Lowercase every address and hash first.
|
|
38
|
+
|
|
39
|
+
## Units of fee fields
|
|
40
|
+
|
|
41
|
+
- `FeeUpdate.fee` is a rate. It is a fraction scaled by 1e18. `10n ** 18n` means 100 percent. The amount is `amount * fee / 10n ** 18n`.
|
|
42
|
+
- `UserRequest.feeAmount` is the fee the omnibridge took. It is in base units of the origin token. `null` means no fee log was seen, which in practice means the fee was zero.
|
|
43
|
+
- Read `feeAmount` for the fee actually taken. `feeUpdate.fee` is the rate that was configured at the time. That is a different fact.
|
|
44
|
+
- `BigInt` fields arrive as decimal strings. `Numeric` fields arrive as a number or a string.
|
|
45
|
+
|
|
46
|
+
## Schema snapshot and codegen
|
|
47
|
+
|
|
48
|
+
`schema.graphql` is a committed snapshot of the indexer schema. `src/graphql.ts` is generated from it. Codegen never contacts a live host.
|
|
49
|
+
|
|
50
|
+
| Script | What it does |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `yarn codegen` | Regenerates `src/graphql.ts` from `schema.graphql`. Offline. |
|
|
53
|
+
| `yarn schema:update` | Introspects the live next indexer and rewrites `schema.graphql`. |
|
|
54
|
+
| `yarn schema:check` | Exits 1 when the live schema differs from the snapshot. Not run in continuous integration. Run it by hand before a release. |
|
|
55
|
+
|
|
56
|
+
To follow a schema change, run `yarn schema:update`, then `yarn codegen`, then the tests. A test fails when the snapshot and the generated types disagree. A schema change cannot ship without regenerating.
|
|
57
|
+
|
|
58
|
+
`schema:update` and `schema:check` accept an address as a second word, for example `node scripts/schema-snapshot.mjs check https://indexer.gibs.finance/graphql`.
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
ISC. See `LICENSE`.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { BridgeKey } from '@gibs/bridge-sdk/types';
|
|
2
|
+
import type { Block, Hex } from 'viem';
|
|
3
|
+
export declare const bridgeStatuses: {
|
|
4
|
+
readonly SUBMITTED: "SUBMITTED";
|
|
5
|
+
readonly MINED: "MINED";
|
|
6
|
+
readonly FINALIZED: "FINALIZED";
|
|
7
|
+
readonly VALIDATING: "VALIDATING";
|
|
8
|
+
readonly AFFIRMED: "AFFIRMED";
|
|
9
|
+
readonly DELIVERED: "DELIVERED";
|
|
10
|
+
};
|
|
11
|
+
export type BridgeStatus = keyof typeof bridgeStatuses;
|
|
12
|
+
export type LiveBridgeStatusParams = {
|
|
13
|
+
hash: Hex;
|
|
14
|
+
ticker: Block;
|
|
15
|
+
bridgeKey: BridgeKey;
|
|
16
|
+
};
|
|
17
|
+
export type ContinuedLiveBridgeStatusParams = LiveBridgeStatusParams & {
|
|
18
|
+
status: BridgeStatus;
|
|
19
|
+
statusIndex: number;
|
|
20
|
+
receipt?: {
|
|
21
|
+
blockNumber: bigint;
|
|
22
|
+
transactionHash: Hex;
|
|
23
|
+
};
|
|
24
|
+
finalizedBlock: {
|
|
25
|
+
number: bigint;
|
|
26
|
+
};
|
|
27
|
+
messageId?: Hex;
|
|
28
|
+
deliveredHash?: Hex;
|
|
29
|
+
count?: number;
|
|
30
|
+
requiredSignatures?: number | null;
|
|
31
|
+
/** null = main bridge; 'gas+' | 'fixed' | 'percentage' = gibs-routed */
|
|
32
|
+
deliveryType?: string | null;
|
|
33
|
+
/**
|
|
34
|
+
* The fields a manual release needs to build its calldata, present only
|
|
35
|
+
* once the live poll has resolved a `messageId` (stage two). A history row
|
|
36
|
+
* replayed through `createBridgeStatusFromHistory` never sets these — that
|
|
37
|
+
* path only feeds `bridgeETA.calculateETA`, which reads `status` alone.
|
|
38
|
+
*/
|
|
39
|
+
release?: {
|
|
40
|
+
requestType: string;
|
|
41
|
+
encodedData: Hex;
|
|
42
|
+
signatures: string[];
|
|
43
|
+
destinationAmbAddress: Hex;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* The ordered list of bridge statuses, mirroring insertion order of
|
|
48
|
+
* {@link bridgeStatuses}. Its index positions encode lifecycle progression so a
|
|
49
|
+
* later status compares greater than an earlier one.
|
|
50
|
+
*/
|
|
51
|
+
export declare const statusList: ("SUBMITTED" | "MINED" | "FINALIZED" | "VALIDATING" | "AFFIRMED" | "DELIVERED")[];
|
|
52
|
+
/**
|
|
53
|
+
* Returns the lifecycle position of a bridge status within {@link statusList}.
|
|
54
|
+
* Used to compare two statuses by progression rather than by name.
|
|
55
|
+
* @param status - the status to locate
|
|
56
|
+
* @returns the zero-based index of the status, or -1 when unknown
|
|
57
|
+
*/
|
|
58
|
+
export declare const statusToIndex: (status: BridgeStatus) => number;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const bridgeStatuses = {
|
|
2
|
+
SUBMITTED: 'SUBMITTED',
|
|
3
|
+
MINED: 'MINED',
|
|
4
|
+
FINALIZED: 'FINALIZED',
|
|
5
|
+
VALIDATING: 'VALIDATING',
|
|
6
|
+
AFFIRMED: 'AFFIRMED',
|
|
7
|
+
DELIVERED: 'DELIVERED',
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The ordered list of bridge statuses, mirroring insertion order of
|
|
11
|
+
* {@link bridgeStatuses}. Its index positions encode lifecycle progression so a
|
|
12
|
+
* later status compares greater than an earlier one.
|
|
13
|
+
*/
|
|
14
|
+
export const statusList = Object.values(bridgeStatuses);
|
|
15
|
+
/**
|
|
16
|
+
* Returns the lifecycle position of a bridge status within {@link statusList}.
|
|
17
|
+
* Used to compare two statuses by progression rather than by name.
|
|
18
|
+
* @param status - the status to locate
|
|
19
|
+
* @returns the zero-based index of the status, or -1 when unknown
|
|
20
|
+
*/
|
|
21
|
+
export const statusToIndex = (status) => {
|
|
22
|
+
return statusList.indexOf(status);
|
|
23
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { GraphQLClient } from 'graphql-request';
|
|
2
|
+
/**
|
|
3
|
+
* WHICH INDEXER THIS PACKAGE READS, AND HOW A CONSUMER CHANGES IT.
|
|
4
|
+
*
|
|
5
|
+
* The interface this code came from held the address as a build-time constant
|
|
6
|
+
* substituted at bundle time, which is the right shape for one application and
|
|
7
|
+
* the wrong shape for a library: a package cannot be rebuilt per consumer, and
|
|
8
|
+
* somebody running against their own indexer, a fork, or a local Ponder has no
|
|
9
|
+
* way to say so.
|
|
10
|
+
*
|
|
11
|
+
* So the address is state with a setter rather than a constant. ONE client is
|
|
12
|
+
* held rather than one per call because `GraphQLClient` is a thin wrapper whose
|
|
13
|
+
* construction is not free, and every query in this package goes to the same
|
|
14
|
+
* host.
|
|
15
|
+
*
|
|
16
|
+
* THE DEFAULT IS THE NEXT INDEXER, "for now" (owner decision), so a consumer who
|
|
17
|
+
* configures nothing still reads real data rather than failing against an empty
|
|
18
|
+
* address. It tracks the current schema; production `indexer.gibs.finance` may
|
|
19
|
+
* lag it.
|
|
20
|
+
*
|
|
21
|
+
* NOTHING RUNS AT MODULE LOAD. The client is created on first use, so importing
|
|
22
|
+
* this package has no side effects.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DEFAULT_INDEXER_ENDPOINT = "https://next-indexer.gibs.finance";
|
|
25
|
+
/**
|
|
26
|
+
* Points this package at an indexer.
|
|
27
|
+
*
|
|
28
|
+
* Call it once, before any query. Calling it again drops the cached client, which
|
|
29
|
+
* abandons nothing — a request already in flight keeps the client that issued
|
|
30
|
+
* it and settles normally.
|
|
31
|
+
*
|
|
32
|
+
* Returns early on an unchanged address so a consumer may call this from a
|
|
33
|
+
* render or an effect without discarding a warm client on every pass.
|
|
34
|
+
*
|
|
35
|
+
* @param url - the indexer's GraphQL address.
|
|
36
|
+
*/
|
|
37
|
+
export declare const setIndexerEndpoint: (url: string) => void;
|
|
38
|
+
/** The indexer address currently in force. */
|
|
39
|
+
export declare const indexerEndpoint: () => string;
|
|
40
|
+
/**
|
|
41
|
+
* The client every query in this package uses.
|
|
42
|
+
*
|
|
43
|
+
* A FUNCTION RATHER THAN THE CLIENT ITSELF, so a module that imports this at
|
|
44
|
+
* load time still sees a later {@link setIndexerEndpoint}. Exporting the value
|
|
45
|
+
* would freeze whichever host happened to be configured at the moment the
|
|
46
|
+
* importing module was first evaluated — which, for a consumer that configures
|
|
47
|
+
* the address during startup, is reliably the wrong one.
|
|
48
|
+
*/
|
|
49
|
+
export declare const indexerClient: () => GraphQLClient;
|
package/dist/endpoint.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { GraphQLClient } from 'graphql-request';
|
|
2
|
+
/**
|
|
3
|
+
* WHICH INDEXER THIS PACKAGE READS, AND HOW A CONSUMER CHANGES IT.
|
|
4
|
+
*
|
|
5
|
+
* The interface this code came from held the address as a build-time constant
|
|
6
|
+
* substituted at bundle time, which is the right shape for one application and
|
|
7
|
+
* the wrong shape for a library: a package cannot be rebuilt per consumer, and
|
|
8
|
+
* somebody running against their own indexer, a fork, or a local Ponder has no
|
|
9
|
+
* way to say so.
|
|
10
|
+
*
|
|
11
|
+
* So the address is state with a setter rather than a constant. ONE client is
|
|
12
|
+
* held rather than one per call because `GraphQLClient` is a thin wrapper whose
|
|
13
|
+
* construction is not free, and every query in this package goes to the same
|
|
14
|
+
* host.
|
|
15
|
+
*
|
|
16
|
+
* THE DEFAULT IS THE NEXT INDEXER, "for now" (owner decision), so a consumer who
|
|
17
|
+
* configures nothing still reads real data rather than failing against an empty
|
|
18
|
+
* address. It tracks the current schema; production `indexer.gibs.finance` may
|
|
19
|
+
* lag it.
|
|
20
|
+
*
|
|
21
|
+
* NOTHING RUNS AT MODULE LOAD. The client is created on first use, so importing
|
|
22
|
+
* this package has no side effects.
|
|
23
|
+
*/
|
|
24
|
+
export const DEFAULT_INDEXER_ENDPOINT = 'https://next-indexer.gibs.finance';
|
|
25
|
+
let endpoint = DEFAULT_INDEXER_ENDPOINT;
|
|
26
|
+
let client = null;
|
|
27
|
+
/**
|
|
28
|
+
* Points this package at an indexer.
|
|
29
|
+
*
|
|
30
|
+
* Call it once, before any query. Calling it again drops the cached client, which
|
|
31
|
+
* abandons nothing — a request already in flight keeps the client that issued
|
|
32
|
+
* it and settles normally.
|
|
33
|
+
*
|
|
34
|
+
* Returns early on an unchanged address so a consumer may call this from a
|
|
35
|
+
* render or an effect without discarding a warm client on every pass.
|
|
36
|
+
*
|
|
37
|
+
* @param url - the indexer's GraphQL address.
|
|
38
|
+
*/
|
|
39
|
+
export const setIndexerEndpoint = (url) => {
|
|
40
|
+
if (url === endpoint)
|
|
41
|
+
return;
|
|
42
|
+
endpoint = url;
|
|
43
|
+
client = null;
|
|
44
|
+
};
|
|
45
|
+
/** The indexer address currently in force. */
|
|
46
|
+
export const indexerEndpoint = () => endpoint;
|
|
47
|
+
/**
|
|
48
|
+
* The client every query in this package uses.
|
|
49
|
+
*
|
|
50
|
+
* A FUNCTION RATHER THAN THE CLIENT ITSELF, so a module that imports this at
|
|
51
|
+
* load time still sees a later {@link setIndexerEndpoint}. Exporting the value
|
|
52
|
+
* would freeze whichever host happened to be configured at the moment the
|
|
53
|
+
* importing module was first evaluated — which, for a consumer that configures
|
|
54
|
+
* the address during startup, is reliably the wrong one.
|
|
55
|
+
*/
|
|
56
|
+
export const indexerClient = () => {
|
|
57
|
+
client ??= new GraphQLClient(endpoint);
|
|
58
|
+
return client;
|
|
59
|
+
};
|