Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a27a20faee | |||
| 5ae6dbfc3f |
18
README.md
18
README.md
@@ -145,6 +145,24 @@ await sdk.transactionType.delete('my-type');
|
|||||||
const block = await sdk.block.get('block-id');
|
const block = await sdk.block.get('block-id');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Interchain trace
|
||||||
|
|
||||||
|
`transaction.getInterchain` / `block.getInterchain` trace a prime block to the
|
||||||
|
public-chain anchors covering it. By default they return the **first anchor per
|
||||||
|
chain** (anchor proofs are chained, so the earliest per chain is the meaningful
|
||||||
|
one). Tune with options:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Default: first anchor per chain (ETH, BTC, …)
|
||||||
|
const trace = await sdk.block.getInterchain('42');
|
||||||
|
|
||||||
|
// Up to 3 anchors per chain
|
||||||
|
await sdk.block.getInterchain('42', { perChain: 3 });
|
||||||
|
|
||||||
|
// All anchors, only the ETH-mainnet chain ("1"); "0" = BTC
|
||||||
|
await sdk.block.getInterchain('42', { perChain: 0, chains: ['1'] });
|
||||||
|
```
|
||||||
|
|
||||||
### Proof Measure (public, unauthenticated)
|
### Proof Measure (public, unauthenticated)
|
||||||
|
|
||||||
`proof-measure` is a separate, **public, unauthenticated** Dragonchain service
|
`proof-measure` is a separate, **public, unauthenticated** Dragonchain service
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@dragonchain-inc/prime-sdk",
|
"name": "@dragonchain-inc/prime-sdk",
|
||||||
"version": "1.4.0",
|
"version": "1.5.0",
|
||||||
"description": "Official Dragonchain Prime SDK for Node.js and TypeScript",
|
"description": "Official Dragonchain Prime SDK for Node.js and TypeScript",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DragonchainClient } from './client';
|
import { DragonchainClient } from './client';
|
||||||
|
import { InterchainOptions, buildInterchainQuery } from './interchain';
|
||||||
import { Block, InterchainTrace } from './types';
|
import { Block, InterchainTrace } from './types';
|
||||||
|
|
||||||
export class BlockClient {
|
export class BlockClient {
|
||||||
@@ -23,7 +24,9 @@ export class BlockClient {
|
|||||||
* Traces a block to the validator (verification) blocks that validated it and
|
* Traces a block to the validator (verification) blocks that validated it and
|
||||||
* the public-chain interchain anchors those validator blocks were bundled into.
|
* the public-chain interchain anchors those validator blocks were bundled into.
|
||||||
*/
|
*/
|
||||||
async getInterchain(blockId: string): Promise<InterchainTrace> {
|
async getInterchain(blockId: string, options?: InterchainOptions): Promise<InterchainTrace> {
|
||||||
return this.client.get<InterchainTrace>(`/api/v1/block/${blockId}/interchain`);
|
return this.client.get<InterchainTrace>(
|
||||||
|
`/api/v1/block/${blockId}/interchain${buildInterchainQuery(options)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export { BlockClient } from './block';
|
|||||||
export { SystemClient } from './system';
|
export { SystemClient } from './system';
|
||||||
export { ProofMeasureClient, PROOF_MEASURE_DEFAULT_BASE_URL } from './proofMeasure';
|
export { ProofMeasureClient, PROOF_MEASURE_DEFAULT_BASE_URL } from './proofMeasure';
|
||||||
export { UnauthHttpClient, UnauthClientConfig } from './unauthHttpClient';
|
export { UnauthHttpClient, UnauthClientConfig } from './unauthHttpClient';
|
||||||
|
export { InterchainOptions, buildInterchainQuery } from './interchain';
|
||||||
|
|
||||||
// Default export
|
// Default export
|
||||||
export default DragonchainSDK;
|
export default DragonchainSDK;
|
||||||
|
|||||||
37
src/interchain.ts
Normal file
37
src/interchain.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Options + query builder for the interchain-trace endpoints
|
||||||
|
* (transaction.getInterchain / block.getInterchain).
|
||||||
|
*
|
||||||
|
* Anchor proofs are chained, so by default the trace returns the first anchor
|
||||||
|
* per public chain; these options change how many and which chains are returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface InterchainOptions {
|
||||||
|
/**
|
||||||
|
* Max interchain anchors returned per public chain, earliest-first.
|
||||||
|
* 1 = the first anchor per chain (the service default); 0 = all anchors.
|
||||||
|
*/
|
||||||
|
perChain?: number;
|
||||||
|
/**
|
||||||
|
* Interchain chain ids to include ("1" = ETH mainnet, "0" = BTC; testnet ids
|
||||||
|
* differ). Omit to include every chain found.
|
||||||
|
*/
|
||||||
|
chains?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the "?perChain=...&chains=..." suffix for the interchain trace
|
||||||
|
* endpoints. Returns "" when no options are set (the server then applies its
|
||||||
|
* defaults: one anchor per chain, all chains).
|
||||||
|
*/
|
||||||
|
export function buildInterchainQuery(options?: InterchainOptions): string {
|
||||||
|
if (!options) return '';
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (options.perChain !== undefined) {
|
||||||
|
parts.push(`perChain=${encodeURIComponent(String(options.perChain))}`);
|
||||||
|
}
|
||||||
|
if (options.chains && options.chains.length > 0) {
|
||||||
|
parts.push(`chains=${options.chains.map(encodeURIComponent).join(',')}`);
|
||||||
|
}
|
||||||
|
return parts.length ? `?${parts.join('&')}` : '';
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DragonchainClient } from './client';
|
import { DragonchainClient } from './client';
|
||||||
|
import { InterchainOptions, buildInterchainQuery } from './interchain';
|
||||||
import {
|
import {
|
||||||
ContentType,
|
ContentType,
|
||||||
TransactionCreateRequest,
|
TransactionCreateRequest,
|
||||||
@@ -56,8 +57,13 @@ export class TransactionClient {
|
|||||||
* blocks were bundled into. If the transaction is still pending (not yet in a
|
* blocks were bundled into. If the transaction is still pending (not yet in a
|
||||||
* block) the trace's arrays are empty.
|
* block) the trace's arrays are empty.
|
||||||
*/
|
*/
|
||||||
async getInterchain(transactionId: string): Promise<InterchainTrace> {
|
async getInterchain(
|
||||||
return this.client.get<InterchainTrace>(`/api/v1/transaction/${transactionId}/interchain`);
|
transactionId: string,
|
||||||
|
options?: InterchainOptions
|
||||||
|
): Promise<InterchainTrace> {
|
||||||
|
return this.client.get<InterchainTrace>(
|
||||||
|
`/api/v1/transaction/${transactionId}/interchain${buildInterchainQuery(options)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
12
src/types.ts
12
src/types.ts
@@ -149,6 +149,12 @@ export interface VerificationBlock {
|
|||||||
version: string;
|
version: string;
|
||||||
primeChainId: string;
|
primeChainId: string;
|
||||||
primeBlockId: string;
|
primeBlockId: string;
|
||||||
|
/**
|
||||||
|
* The prime block's proof this validator block attests to. Part of the signed
|
||||||
|
* message (blake2b-256 over version|primeChainId|primeBlockId|primeBlockProof|
|
||||||
|
* timestamp|verifierPublicKey), so it is required to verify verifierSignature.
|
||||||
|
*/
|
||||||
|
primeBlockProof: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
verifierPublicKey: string;
|
verifierPublicKey: string;
|
||||||
verifierSignature: string;
|
verifierSignature: string;
|
||||||
@@ -163,9 +169,15 @@ export interface InterchainTransaction {
|
|||||||
id: number;
|
id: number;
|
||||||
version: string;
|
version: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
|
/** Numeric external network id ("1"=ETH, "0"=BTC, ...). May be absent for chains without one. */
|
||||||
chainId: string;
|
chainId: string;
|
||||||
|
/** Explicit external chain name ("ETH", "BTC", "BASE", "BNB") — authoritative. */
|
||||||
|
chainName: string;
|
||||||
transHash: string;
|
transHash: string;
|
||||||
|
/** External chain block the anchor confirmed in; empty until confirmed (see status). */
|
||||||
blockId: string;
|
blockId: string;
|
||||||
|
/** Confirmation state: "pending" | "confirmed" | "dropped". */
|
||||||
|
status: string;
|
||||||
validatorBlocks: string[];
|
validatorBlocks: string[];
|
||||||
validatorBlockhash: string;
|
validatorBlockhash: string;
|
||||||
signature: string;
|
signature: string;
|
||||||
|
|||||||
27
tests/interchain.test.ts
Normal file
27
tests/interchain.test.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { buildInterchainQuery } from '../src/interchain';
|
||||||
|
|
||||||
|
describe('buildInterchainQuery', () => {
|
||||||
|
it('returns empty string with no options', () => {
|
||||||
|
expect(buildInterchainQuery()).toBe('');
|
||||||
|
expect(buildInterchainQuery({})).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('encodes perChain (including 0 for all)', () => {
|
||||||
|
expect(buildInterchainQuery({ perChain: 1 })).toBe('?perChain=1');
|
||||||
|
expect(buildInterchainQuery({ perChain: 0 })).toBe('?perChain=0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('joins chains with commas', () => {
|
||||||
|
expect(buildInterchainQuery({ chains: ['1', '0'] })).toBe('?chains=1,0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('combines perChain and chains', () => {
|
||||||
|
expect(buildInterchainQuery({ perChain: 2, chains: ['1', '0'] })).toBe(
|
||||||
|
'?perChain=2&chains=1,0'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores an empty chains array', () => {
|
||||||
|
expect(buildInterchainQuery({ chains: [] })).toBe('');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user