@indigo-labs/indigo-sdk 0.5.5 → 0.5.7

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.
Files changed (208) hide show
  1. package/dist/index.d.mts +4 -2
  2. package/dist/index.d.ts +4 -2
  3. package/dist/index.js +6 -3
  4. package/dist/index.mjs +5 -3
  5. package/package.json +11 -1
  6. package/.claude/settings.local.json +0 -7
  7. package/.github/workflows/ci.yml +0 -66
  8. package/.husky/pre-commit +0 -1
  9. package/.nvmrc +0 -1
  10. package/.prettierignore +0 -1
  11. package/.prettierrc +0 -6
  12. package/eslint.config.mjs +0 -42
  13. package/scripts/bench.sh +0 -62
  14. package/scripts/run-repeat.sh +0 -22
  15. package/src/contracts/cdp/helpers.ts +0 -173
  16. package/src/contracts/cdp/scripts.ts +0 -70
  17. package/src/contracts/cdp/transactions.ts +0 -1584
  18. package/src/contracts/cdp/types-new.ts +0 -277
  19. package/src/contracts/cdp/types.ts +0 -43
  20. package/src/contracts/cdp-creator/queries.ts +0 -30
  21. package/src/contracts/cdp-creator/scripts.ts +0 -45
  22. package/src/contracts/cdp-creator/types-new.ts +0 -50
  23. package/src/contracts/cdp-creator/types.ts +0 -24
  24. package/src/contracts/collector/scripts.ts +0 -32
  25. package/src/contracts/collector/transactions.ts +0 -50
  26. package/src/contracts/collector/types-new.ts +0 -17
  27. package/src/contracts/execute/scripts.ts +0 -57
  28. package/src/contracts/execute/types-new.ts +0 -44
  29. package/src/contracts/execute/types.ts +0 -24
  30. package/src/contracts/gov/helpers.ts +0 -351
  31. package/src/contracts/gov/scripts.ts +0 -41
  32. package/src/contracts/gov/transactions.ts +0 -1607
  33. package/src/contracts/gov/types-new.ts +0 -268
  34. package/src/contracts/gov/types.ts +0 -22
  35. package/src/contracts/iasset/helpers.ts +0 -170
  36. package/src/contracts/iasset/queries.ts +0 -102
  37. package/src/contracts/iasset/scripts.ts +0 -38
  38. package/src/contracts/iasset/types.ts +0 -154
  39. package/src/contracts/initialize/actions.ts +0 -789
  40. package/src/contracts/initialize/helpers.ts +0 -616
  41. package/src/contracts/initialize/types.ts +0 -116
  42. package/src/contracts/interest-collection/helpers.ts +0 -19
  43. package/src/contracts/interest-collection/queries.ts +0 -66
  44. package/src/contracts/interest-collection/scripts.ts +0 -44
  45. package/src/contracts/interest-collection/transactions.ts +0 -433
  46. package/src/contracts/interest-collection/types-new.ts +0 -50
  47. package/src/contracts/interest-collection/types.ts +0 -26
  48. package/src/contracts/interest-oracle/helpers.ts +0 -61
  49. package/src/contracts/interest-oracle/scripts.ts +0 -18
  50. package/src/contracts/interest-oracle/transactions.ts +0 -151
  51. package/src/contracts/interest-oracle/types-new.ts +0 -32
  52. package/src/contracts/interest-oracle/types.ts +0 -16
  53. package/src/contracts/one-shot/scripts.ts +0 -12
  54. package/src/contracts/one-shot/transactions.ts +0 -66
  55. package/src/contracts/one-shot/types.ts +0 -22
  56. package/src/contracts/poll/helpers.ts +0 -37
  57. package/src/contracts/poll/scripts.ts +0 -71
  58. package/src/contracts/poll/types-poll-manager.ts +0 -20
  59. package/src/contracts/poll/types-poll-new.ts +0 -196
  60. package/src/contracts/poll/types-poll-shard.ts +0 -16
  61. package/src/contracts/price-oracle/helpers.ts +0 -30
  62. package/src/contracts/price-oracle/scripts.ts +0 -18
  63. package/src/contracts/price-oracle/transactions.ts +0 -115
  64. package/src/contracts/price-oracle/types-new.ts +0 -50
  65. package/src/contracts/price-oracle/types.ts +0 -16
  66. package/src/contracts/pyth-feed/helpers.ts +0 -82
  67. package/src/contracts/pyth-feed/scripts.ts +0 -15
  68. package/src/contracts/pyth-feed/types.ts +0 -181
  69. package/src/contracts/rob/helpers.ts +0 -666
  70. package/src/contracts/rob/scripts.ts +0 -35
  71. package/src/contracts/rob/transactions.ts +0 -423
  72. package/src/contracts/rob/types-new.ts +0 -128
  73. package/src/contracts/rob/types.ts +0 -16
  74. package/src/contracts/rob-leverage/helpers.ts +0 -422
  75. package/src/contracts/rob-leverage/transactions.ts +0 -368
  76. package/src/contracts/stability-pool/helpers.ts +0 -798
  77. package/src/contracts/stability-pool/queries.ts +0 -132
  78. package/src/contracts/stability-pool/scripts.ts +0 -51
  79. package/src/contracts/stability-pool/transactions.ts +0 -921
  80. package/src/contracts/stability-pool/types-new.ts +0 -385
  81. package/src/contracts/stability-pool/types.ts +0 -25
  82. package/src/contracts/stableswap/helpers.ts +0 -507
  83. package/src/contracts/stableswap/scripts.ts +0 -37
  84. package/src/contracts/stableswap/transactions.ts +0 -475
  85. package/src/contracts/stableswap/types-new.ts +0 -131
  86. package/src/contracts/stableswap/types.ts +0 -17
  87. package/src/contracts/staking/helpers.ts +0 -136
  88. package/src/contracts/staking/scripts.ts +0 -41
  89. package/src/contracts/staking/transactions.ts +0 -349
  90. package/src/contracts/staking/types-new.ts +0 -137
  91. package/src/contracts/staking/types.ts +0 -17
  92. package/src/contracts/treasury/helpers.ts +0 -21
  93. package/src/contracts/treasury/queries.ts +0 -100
  94. package/src/contracts/treasury/scripts.ts +0 -27
  95. package/src/contracts/treasury/transactions.ts +0 -334
  96. package/src/contracts/treasury/types-new.ts +0 -69
  97. package/src/contracts/treasury/types.ts +0 -14
  98. package/src/contracts/version-registry/scripts.ts +0 -29
  99. package/src/contracts/version-registry/types-new.ts +0 -18
  100. package/src/contracts/version-registry/types.ts +0 -17
  101. package/src/index.ts +0 -99
  102. package/src/scripts/always-fail-validator.ts +0 -7
  103. package/src/scripts/auth-token-policy.ts +0 -24
  104. package/src/scripts/iasset-policy.ts +0 -23
  105. package/src/types/evolution-schema-options.ts +0 -16
  106. package/src/types/generic.ts +0 -52
  107. package/src/types/multisig.ts +0 -48
  108. package/src/types/on-chain-decimal.ts +0 -57
  109. package/src/types/rational.ts +0 -76
  110. package/src/types/system-params.ts +0 -463
  111. package/src/utils/array-utils.ts +0 -108
  112. package/src/utils/bigint-utils.ts +0 -35
  113. package/src/utils/helper-txs.ts +0 -31
  114. package/src/utils/indigo-helpers.ts +0 -17
  115. package/src/utils/lucid-utils.ts +0 -125
  116. package/src/utils/oracle-helpers.ts +0 -62
  117. package/src/utils/pyth/decode.ts +0 -223
  118. package/src/utils/pyth/encode.ts +0 -262
  119. package/src/utils/pyth/index.ts +0 -14
  120. package/src/utils/pyth/types.ts +0 -87
  121. package/src/utils/time-helpers.ts +0 -4
  122. package/src/utils/utils.ts +0 -25
  123. package/src/validators/always-succeed-validator.ts +0 -6
  124. package/src/validators/cdp-creator-validator.ts +0 -7
  125. package/src/validators/cdp-redeem-validator.ts +0 -7
  126. package/src/validators/cdp-validator.ts +0 -7
  127. package/src/validators/collector-validator.ts +0 -7
  128. package/src/validators/execute-validator.ts +0 -7
  129. package/src/validators/governance-validator.ts +0 -7
  130. package/src/validators/iasset-validator.ts +0 -7
  131. package/src/validators/interest-collection-validator.ts +0 -7
  132. package/src/validators/interest-oracle-validator.ts +0 -7
  133. package/src/validators/one-shot-policy.ts +0 -7
  134. package/src/validators/poll-manager-validator.ts +0 -7
  135. package/src/validators/poll-shard-validator.ts +0 -7
  136. package/src/validators/price-oracle-validator.ts +0 -7
  137. package/src/validators/pyth-feed-validator.ts +0 -7
  138. package/src/validators/rob-validator.ts +0 -7
  139. package/src/validators/stability-pool-validator.ts +0 -7
  140. package/src/validators/stableswap-validator.ts +0 -7
  141. package/src/validators/staking-validator.ts +0 -7
  142. package/src/validators/treasury-validator.ts +0 -7
  143. package/src/validators/version-record-policy.ts +0 -7
  144. package/src/validators/version-registry-validator.ts +0 -7
  145. package/tests/always-succeed/script.ts +0 -7
  146. package/tests/array-utils.test.ts +0 -92
  147. package/tests/bigint-utils.test.ts +0 -41
  148. package/tests/cdp/actions.ts +0 -680
  149. package/tests/cdp/cdp-helpers.ts +0 -55
  150. package/tests/cdp/cdp-queries.ts +0 -423
  151. package/tests/cdp/cdp.test.ts +0 -6730
  152. package/tests/cdp/transactions-mutated.ts +0 -1733
  153. package/tests/data/system-params.json +0 -1155
  154. package/tests/datums.test.ts +0 -302
  155. package/tests/endpoints/initialize.ts +0 -78
  156. package/tests/endpoints/interest-collector.ts +0 -37
  157. package/tests/endpoints/treasury.ts +0 -70
  158. package/tests/gov/actions.ts +0 -381
  159. package/tests/gov/gov.test.ts +0 -5147
  160. package/tests/gov/governance-queries.ts +0 -37
  161. package/tests/hash-checks.test.ts +0 -112
  162. package/tests/indigo-test-helpers.ts +0 -99
  163. package/tests/initialize.test.ts +0 -79
  164. package/tests/interest-calculations.test.ts +0 -120
  165. package/tests/interest-collection/interest-collection.test.ts +0 -843
  166. package/tests/interest-collection/transactions-mutated.ts +0 -260
  167. package/tests/interest-oracle.test.ts +0 -93
  168. package/tests/mock/assets-mock.ts +0 -243
  169. package/tests/mock/protocol-params-mock.ts +0 -21
  170. package/tests/price-oracle/actions.ts +0 -161
  171. package/tests/price-oracle/price-oracle-queries.ts +0 -12
  172. package/tests/price-oracle/price-oracle.test.ts +0 -228
  173. package/tests/price-oracle/transactions-mutated.ts +0 -59
  174. package/tests/pyth/endpoints.ts +0 -96
  175. package/tests/pyth/helpers.ts +0 -37
  176. package/tests/pyth/pyth-encoding.test.ts +0 -376
  177. package/tests/pyth/pyth-feeds.test.ts +0 -943
  178. package/tests/pyth/pyth-indigo.test.ts +0 -505
  179. package/tests/pyth/pyth.test.ts +0 -299
  180. package/tests/queries/collector-queries.ts +0 -27
  181. package/tests/queries/execute-queries.ts +0 -47
  182. package/tests/queries/iasset-queries.ts +0 -149
  183. package/tests/queries/interest-oracle-queries.ts +0 -12
  184. package/tests/queries/poll-queries.ts +0 -97
  185. package/tests/queries/staking-queries.ts +0 -54
  186. package/tests/rob/actions.ts +0 -56
  187. package/tests/rob/rob-leverage.test.ts +0 -2555
  188. package/tests/rob/rob-queries.ts +0 -95
  189. package/tests/rob/rob.test.ts +0 -3677
  190. package/tests/rob/transactions-mutated.ts +0 -844
  191. package/tests/script-size.test.ts +0 -240
  192. package/tests/setup.ts +0 -135
  193. package/tests/stability-pool/actions.ts +0 -229
  194. package/tests/stability-pool.test.ts +0 -6491
  195. package/tests/stableswap/stableswap-actions.ts +0 -83
  196. package/tests/stableswap/stableswap-queries.ts +0 -98
  197. package/tests/stableswap/stableswap.test.ts +0 -4471
  198. package/tests/stableswap/transactions-mutated.ts +0 -348
  199. package/tests/staking.test.ts +0 -172
  200. package/tests/test-helpers.ts +0 -94
  201. package/tests/treasury/actions.ts +0 -67
  202. package/tests/treasury/treasury.test.ts +0 -320
  203. package/tests/utils/asserts.ts +0 -87
  204. package/tests/utils/benchmark-utils.ts +0 -130
  205. package/tests/utils/index.ts +0 -168
  206. package/tsconfig.build.json +0 -4
  207. package/tsconfig.json +0 -27
  208. package/vitest.config.ts +0 -11
@@ -1,125 +0,0 @@
1
- import {
2
- addAssets,
3
- Address,
4
- Assets,
5
- calculateMinLovelaceFromUTxO,
6
- Credential,
7
- credentialToAddress,
8
- Data,
9
- Datum,
10
- LucidEvolution,
11
- Network,
12
- OutputDatum,
13
- OutRef,
14
- paymentCredentialOf,
15
- ProtocolParameters,
16
- Script,
17
- ScriptHash,
18
- scriptHashToCredential,
19
- stakeCredentialOf,
20
- TxBuilder,
21
- UTxO,
22
- } from '@lucid-evolution/lucid';
23
- import { ScriptReference } from '../types/system-params';
24
- import { match, P } from 'ts-pattern';
25
-
26
- /**
27
- * Returns the inline datum.
28
- * Throws when the UTXO doesn't have an inline datum
29
- * (i.e. in case it has hash datum or no datum).
30
- */
31
- export function getInlineDatumOrThrow(utxo: UTxO): Datum {
32
- if (utxo.datum != null) {
33
- return utxo.datum;
34
- }
35
-
36
- throw new Error(
37
- 'Expected an inline datum for OutRef: ' +
38
- JSON.stringify({
39
- txHash: utxo.txHash,
40
- outputIndex: utxo.outputIndex,
41
- } as OutRef),
42
- );
43
- }
44
-
45
- export async function addrDetails(
46
- lucid: LucidEvolution,
47
- ): Promise<[Credential, Credential | undefined]> {
48
- const addr = await lucid.wallet().address();
49
-
50
- let stakeCredential = undefined;
51
- try {
52
- stakeCredential = stakeCredentialOf(addr);
53
- } catch (_) {
54
- // No stake credential
55
- }
56
-
57
- return [paymentCredentialOf(addr), stakeCredential];
58
- }
59
-
60
- export function createScriptAddress(
61
- network: Network,
62
- scriptHash: ScriptHash,
63
- stakeCredential?: Credential,
64
- ): Address {
65
- return credentialToAddress(
66
- network,
67
- scriptHashToCredential(scriptHash),
68
- stakeCredential,
69
- );
70
- }
71
-
72
- export async function scriptRef(
73
- ref: ScriptReference,
74
- lucid: LucidEvolution,
75
- ): Promise<UTxO> {
76
- const utxos = await lucid.utxosByOutRef([
77
- { txHash: ref.input.transactionId, outputIndex: ref.input.index },
78
- ]);
79
- if (utxos.length === 0) throw Error('Unable to locate script ref.');
80
- return utxos[0];
81
- }
82
-
83
- /**
84
- * Complete, sign with wallet, submit a tx and wait for confirmation.
85
- */
86
- export async function submitTx(
87
- lucid: LucidEvolution,
88
- tx: TxBuilder,
89
- ): Promise<void> {
90
- const txHash = await tx
91
- .complete()
92
- .then((t) => t.sign.withWallet().complete())
93
- .then((t) => t.submit());
94
- await lucid.awaitTx(txHash);
95
- }
96
-
97
- export function balance(utxos: UTxO[]): Assets {
98
- return utxos.reduce((acc, utxo) => addAssets(acc, utxo.assets), {});
99
- }
100
-
101
- /**
102
- * Estimate the min lovelace for a UTXO so it can be created.
103
- */
104
- export function estimateUtxoMinLovelace(
105
- protocolParameters: ProtocolParameters,
106
- destinationAddr: string,
107
- assets: Assets,
108
- destinationDatum: OutputDatum | undefined = undefined,
109
- scriptRef: Script | undefined = undefined,
110
- ): bigint {
111
- return calculateMinLovelaceFromUTxO(protocolParameters.coinsPerUtxoByte, {
112
- address: destinationAddr,
113
- datumHash: match(destinationDatum)
114
- .with({ kind: 'hash', value: P.select() }, (dHash) => dHash)
115
- .otherwise(() => null),
116
- datum: match(destinationDatum)
117
- .with({ kind: 'inline', value: P.select() }, (data) => Data.to(data))
118
- .otherwise(() => null),
119
- assets: assets,
120
- // Use dummy tx hash and out idx
121
- txHash: '0000000000000000000000000000000000000000000000000000000000000000',
122
- outputIndex: 0,
123
- scriptRef: scriptRef ?? null,
124
- } satisfies UTxO);
125
- }
@@ -1,62 +0,0 @@
1
- import { match, P } from 'ts-pattern';
2
- import { IAssetPriceInfo } from '../contracts/iasset/types';
3
- import { Rational } from '../types/rational';
4
- import { LucidEvolution, OutRef, UTxO } from '@lucid-evolution/lucid';
5
- import { adjustPriceToDecimals } from '../contracts/cdp/helpers';
6
- import {
7
- AssetClass,
8
- getInlineDatumOrThrow,
9
- matchSingle,
10
- } from '@3rd-eye-labs/cardano-offchain-common';
11
- import { parsePriceOracleDatum } from '../contracts/price-oracle/types-new';
12
- import { derivePythPrice } from '../contracts/pyth-feed/helpers';
13
- import {
14
- fromSysParamsDerivedPythPrice,
15
- getPythFeedConfig,
16
- PythConfig,
17
- } from '../types/system-params';
18
-
19
- export async function retrieveAdjustedPrice(
20
- iasset: Uint8Array<ArrayBufferLike>,
21
- collateralAsset: AssetClass,
22
- priceInfo: IAssetPriceInfo,
23
- extraDecimals: bigint,
24
- priceOracleOref: OutRef | undefined,
25
- pythMessage: string | undefined,
26
- pythConfig: PythConfig,
27
- lucid: LucidEvolution,
28
- ): Promise<[Rational, UTxO | undefined]> {
29
- const [oraclePrice, maybePriceOracleUtxo] = await match(priceInfo)
30
- .with({ OracleNft: P.any }, async () => {
31
- if (!priceOracleOref) throw new Error('Missing price oracle');
32
- const priceOracleUtxo = matchSingle(
33
- await lucid.utxosByOutRef([priceOracleOref]),
34
- (_) => new Error('Expected a single price oracle UTXO'),
35
- );
36
- const priceOracleDatum = parsePriceOracleDatum(
37
- getInlineDatumOrThrow(priceOracleUtxo),
38
- );
39
- return [priceOracleDatum.price, priceOracleUtxo];
40
- })
41
- .with({ Delisted: P.select() }, (price) => [price.price, undefined])
42
- .with({ DeferredValidation: P.select() }, () => {
43
- if (!pythMessage) throw new Error('Missing Pyth message');
44
-
45
- return [
46
- derivePythPrice(
47
- fromSysParamsDerivedPythPrice(
48
- getPythFeedConfig(pythConfig, iasset, collateralAsset).params
49
- .config,
50
- ),
51
- pythMessage,
52
- ),
53
- undefined,
54
- ];
55
- })
56
- .exhaustive();
57
-
58
- return [
59
- adjustPriceToDecimals(extraDecimals, oraclePrice as Rational),
60
- maybePriceOracleUtxo as UTxO | undefined,
61
- ];
62
- }
@@ -1,223 +0,0 @@
1
- import type { PriceUpdate, PythMessageParts } from './types.js';
2
- import type { ParsedFeedPayload } from '@pythnetwork/pyth-lazer-sdk';
3
- import {
4
- MARKET_SESSION_ORDER,
5
- PRICE_UPDATE_MAGIC,
6
- PROP_ID,
7
- SOLANA_FORMAT_MAGIC,
8
- } from './types.js';
9
-
10
- function expectMagic(
11
- buf: Uint8Array,
12
- offset: number,
13
- magic: Uint8Array,
14
- label: string,
15
- ): void {
16
- for (let i = 0; i < magic.length; i++) {
17
- if (buf[offset + i] !== magic[i]) {
18
- throw new Error(`Invalid ${label} magic byte at ${i}`);
19
- }
20
- }
21
- }
22
-
23
- function bigintToSdkNumber(v: bigint): number {
24
- if (
25
- v > BigInt(Number.MAX_SAFE_INTEGER) ||
26
- v < BigInt(Number.MIN_SAFE_INTEGER)
27
- ) {
28
- throw new RangeError('Scalar does not fit in a safe integer');
29
- }
30
- return Number(v);
31
- }
32
-
33
- function decodeFeedPayload(
34
- buf: Uint8Array,
35
- view: DataView,
36
- start: number,
37
- ): { feed: ParsedFeedPayload; next: number } {
38
- let o = start;
39
- if (o + 5 > buf.length) throw new RangeError('Truncated feed header');
40
- const priceFeedId = view.getUint32(o, true);
41
- o += 4;
42
- const nProps = buf[o];
43
- o += 1;
44
- const feed: ParsedFeedPayload = { priceFeedId };
45
- for (let i = 0; i < nProps; i++) {
46
- if (o >= buf.length) throw new RangeError('Truncated feed property header');
47
- const propId = buf[o];
48
- o += 1;
49
- switch (propId) {
50
- case PROP_ID.Price: {
51
- const v = view.getBigInt64(o, true);
52
- o += 8;
53
- if (v !== 0n) feed.price = v.toString();
54
- break;
55
- }
56
- case PROP_ID.BestBidPrice: {
57
- const v = view.getBigInt64(o, true);
58
- o += 8;
59
- if (v !== 0n) feed.bestBidPrice = v.toString();
60
- break;
61
- }
62
- case PROP_ID.BestAskPrice: {
63
- const v = view.getBigInt64(o, true);
64
- o += 8;
65
- if (v !== 0n) feed.bestAskPrice = v.toString();
66
- break;
67
- }
68
- case PROP_ID.PublisherCount: {
69
- feed.publisherCount = view.getUint16(o, true);
70
- o += 2;
71
- break;
72
- }
73
- case PROP_ID.Exponent: {
74
- feed.exponent = view.getInt16(o, true);
75
- o += 2;
76
- break;
77
- }
78
- case PROP_ID.Confidence: {
79
- const v = view.getBigInt64(o, true);
80
- o += 8;
81
- if (v !== 0n) feed.confidence = bigintToSdkNumber(v);
82
- break;
83
- }
84
- case PROP_ID.FundingRate: {
85
- const tag = buf[o];
86
- o += 1;
87
- if (tag === 1) {
88
- const v = view.getBigInt64(o, true);
89
- o += 8;
90
- feed.fundingRate = bigintToSdkNumber(v);
91
- } else if (tag !== 0) {
92
- throw new RangeError('Invalid FundingRate option tag');
93
- }
94
- break;
95
- }
96
- case PROP_ID.FundingTimestamp: {
97
- const tag = buf[o];
98
- o += 1;
99
- if (tag === 1) {
100
- const v = view.getBigUint64(o, true);
101
- o += 8;
102
- feed.fundingTimestamp = bigintToSdkNumber(v);
103
- } else if (tag !== 0) {
104
- throw new RangeError('Invalid FundingTimestamp option tag');
105
- }
106
- break;
107
- }
108
- case PROP_ID.FundingRateInterval: {
109
- const tag = buf[o];
110
- o += 1;
111
- if (tag === 1) {
112
- const v = view.getBigUint64(o, true);
113
- o += 8;
114
- feed.fundingRateInterval = bigintToSdkNumber(v);
115
- } else if (tag !== 0) {
116
- throw new RangeError('Invalid FundingRateInterval option tag');
117
- }
118
- break;
119
- }
120
- case PROP_ID.MarketSession: {
121
- const idx = view.getUint16(o, true);
122
- o += 2;
123
- const session = MARKET_SESSION_ORDER[idx];
124
- if (!session) throw new RangeError('Invalid marketSession index');
125
- feed.marketSession = session;
126
- break;
127
- }
128
- case PROP_ID.EmaPrice: {
129
- const v = view.getBigInt64(o, true);
130
- o += 8;
131
- if (v !== 0n) feed.emaPrice = v.toString();
132
- break;
133
- }
134
- case PROP_ID.EmaConfidence: {
135
- const v = view.getBigInt64(o, true);
136
- o += 8;
137
- if (v !== 0n) feed.emaConfidence = bigintToSdkNumber(v);
138
- break;
139
- }
140
- case PROP_ID.FeedUpdateTimestamp: {
141
- const tag = buf[o];
142
- o += 1;
143
- if (tag === 1) {
144
- const v = view.getBigUint64(o, true);
145
- o += 8;
146
- feed.feedUpdateTimestamp = bigintToSdkNumber(v);
147
- } else if (tag !== 0) {
148
- throw new RangeError('Invalid FeedUpdateTimestamp option tag');
149
- }
150
- break;
151
- }
152
- default:
153
- throw new RangeError(`Unknown feed property id: ${propId}`);
154
- }
155
- }
156
- return { feed, next: o };
157
- }
158
-
159
- /**
160
- * Decode a PriceUpdate payload produced by {@link encodePriceUpdate}.
161
- */
162
- export function decodePriceUpdate(payload: Uint8Array): PriceUpdate {
163
- const min = 4 + 8 + 1 + 1;
164
- if (payload.length < min) {
165
- throw new RangeError('Price update payload too short');
166
- }
167
- expectMagic(payload, 0, PRICE_UPDATE_MAGIC, 'price update');
168
- const view = new DataView(
169
- payload.buffer,
170
- payload.byteOffset,
171
- payload.byteLength,
172
- );
173
- let o = 4;
174
- const timestampUs = view.getBigUint64(o, true);
175
- o += 8;
176
- const channelId = payload[o];
177
- o += 1;
178
- const feedsLen = payload[o];
179
- o += 1;
180
- const priceFeeds: ParsedFeedPayload[] = [];
181
- for (let f = 0; f < feedsLen; f++) {
182
- const decoded = decodeFeedPayload(payload, view, o);
183
- priceFeeds.push(decoded.feed);
184
- o = decoded.next;
185
- }
186
- if (o !== payload.length) {
187
- throw new RangeError('Trailing bytes in price update payload');
188
- }
189
- return {
190
- timestampUs: timestampUs.toString(),
191
- channelId,
192
- priceFeeds,
193
- };
194
- }
195
-
196
- const PYTH_MESSAGE_HEADER_LEN = 4 + 64 + 32 + 2;
197
-
198
- /**
199
- * Decode a Solana-format Pyth message produced by {@link encodePythMessage}.
200
- */
201
- export function decodePythMessage(message: Uint8Array): PythMessageParts {
202
- if (message.length < PYTH_MESSAGE_HEADER_LEN) {
203
- throw new RangeError('Pyth message too short');
204
- }
205
- expectMagic(message, 0, SOLANA_FORMAT_MAGIC, 'Solana format');
206
- const view = new DataView(
207
- message.buffer,
208
- message.byteOffset,
209
- message.byteLength,
210
- );
211
- const payloadLen = view.getUint16(100, true);
212
- const total = PYTH_MESSAGE_HEADER_LEN + payloadLen;
213
- if (message.length !== total) {
214
- throw new RangeError(
215
- `Pyth message length mismatch: expected ${total} bytes, got ${message.length}`,
216
- );
217
- }
218
- return {
219
- signature: message.subarray(4, 68).slice(),
220
- publicKey: message.subarray(68, 100).slice(),
221
- payload: message.subarray(102, total).slice(),
222
- };
223
- }
@@ -1,262 +0,0 @@
1
- import type {
2
- Feed,
3
- MarketSession,
4
- PriceUpdate,
5
- PythMessageParts,
6
- } from './types.js';
7
- import type { ParsedFeedPayload } from '@pythnetwork/pyth-lazer-sdk';
8
- import {
9
- MARKET_SESSION_ORDER,
10
- PRICE_UPDATE_MAGIC,
11
- PROP_ID,
12
- SOLANA_FORMAT_MAGIC,
13
- } from './types.js';
14
-
15
- export { PRICE_UPDATE_MAGIC, SOLANA_FORMAT_MAGIC } from './types.js';
16
-
17
- function u8(b: number): Uint8Array {
18
- if (b < 0 || b > 255) throw new RangeError('u8 out of range');
19
- return new Uint8Array([b & 0xff]);
20
- }
21
-
22
- function u16Le(n: number): Uint8Array {
23
- if (n < 0 || n > 0xffff) throw new RangeError('u16 out of range');
24
- const buf = new Uint8Array(2);
25
- new DataView(buf.buffer).setUint16(0, n, true);
26
- return buf;
27
- }
28
-
29
- function u32Le(n: number): Uint8Array {
30
- if (n < 0 || n > 0xffff_ffff) throw new RangeError('u32 out of range');
31
- const buf = new Uint8Array(4);
32
- new DataView(buf.buffer).setUint32(0, n, true);
33
- return buf;
34
- }
35
-
36
- function u64Le(n: bigint): Uint8Array {
37
- const buf = new Uint8Array(8);
38
- const view = new DataView(buf.buffer);
39
- const lo = Number(n & 0xffff_ffff_ffff_ffffn);
40
- const hi = Number((n >> 32n) & 0xffff_ffffn);
41
- view.setUint32(0, lo & 0xffff_ffff, true);
42
- view.setUint32(4, hi, true);
43
- return buf;
44
- }
45
-
46
- function i16Le(n: number): Uint8Array {
47
- const buf = new Uint8Array(2);
48
- new DataView(buf.buffer).setInt16(0, n, true);
49
- return buf;
50
- }
51
-
52
- function i64Le(n: bigint): Uint8Array {
53
- const buf = new Uint8Array(8);
54
- const view = new DataView(buf.buffer);
55
- const lo = Number(n & 0xffff_ffff_ffff_ffffn);
56
- const hi = Number(Number(n >> 32n) & 0xffff_ffff);
57
- view.setUint32(0, lo & 0xffff_ffff, true);
58
- view.setUint32(4, hi, true);
59
- return buf;
60
- }
61
-
62
- function concat(...chunks: Uint8Array[]): Uint8Array {
63
- const total = chunks.reduce((s, c) => s + c.length, 0);
64
- const out = new Uint8Array(total);
65
- let off = 0;
66
- for (const c of chunks) {
67
- out.set(c, off);
68
- off += c.length;
69
- }
70
- return out;
71
- }
72
-
73
- /** Encode a single feed property (property_id byte + value bytes). */
74
- function encodeFeedProperty(id: number, value: Uint8Array): Uint8Array {
75
- return concat(u8(id), value);
76
- }
77
-
78
- function toFeed(parsed: ParsedFeedPayload): Feed {
79
- const toBigInt = (v: string | number | undefined): bigint | null =>
80
- v === undefined ? null : BigInt(v);
81
-
82
- const toBigIntOptional = (v: string | number | undefined): bigint | null =>
83
- v === undefined ? null : BigInt(v);
84
-
85
- return {
86
- feedId: parsed.priceFeedId,
87
- price: parsed.price === undefined ? null : BigInt(parsed.price),
88
- bestBidPrice: toBigIntOptional(parsed.bestBidPrice),
89
- bestAskPrice: toBigIntOptional(parsed.bestAskPrice),
90
- publisherCount: parsed.publisherCount ?? 0,
91
- exponent: parsed.exponent ?? 0,
92
- confidence: toBigInt(parsed.confidence),
93
- fundingRate: toBigInt(parsed.fundingRate),
94
- fundingTimestamp: toBigInt(parsed.fundingTimestamp),
95
- fundingRateInterval: toBigInt(parsed.fundingRateInterval),
96
- marketSession: (parsed.marketSession as MarketSession) ?? 'Regular',
97
- emaPrice: toBigIntOptional(parsed.emaPrice),
98
- emaConfidence: toBigInt(parsed.emaConfidence),
99
- feedUpdateTimestamp: toBigInt(parsed.feedUpdateTimestamp),
100
- };
101
- }
102
-
103
- /** Encode feed properties that are defined, in the order expected by the parser. */
104
- function encodeFeed(feed: Feed): Uint8Array {
105
- const parts: Uint8Array[] = [];
106
-
107
- if (feed.price !== undefined) {
108
- const v = feed.price === null ? 0n : feed.price;
109
- parts.push(encodeFeedProperty(PROP_ID.Price, i64Le(v)));
110
- }
111
- if (feed.bestBidPrice !== undefined) {
112
- const v = feed.bestBidPrice === null ? 0n : feed.bestBidPrice;
113
- parts.push(encodeFeedProperty(PROP_ID.BestBidPrice, i64Le(v)));
114
- }
115
- if (feed.bestAskPrice !== undefined) {
116
- const v = feed.bestAskPrice === null ? 0n : feed.bestAskPrice;
117
- parts.push(encodeFeedProperty(PROP_ID.BestAskPrice, i64Le(v)));
118
- }
119
- if (feed.publisherCount !== undefined) {
120
- parts.push(
121
- encodeFeedProperty(PROP_ID.PublisherCount, u16Le(feed.publisherCount)),
122
- );
123
- }
124
- if (feed.exponent !== undefined) {
125
- parts.push(encodeFeedProperty(PROP_ID.Exponent, i16Le(feed.exponent)));
126
- }
127
- if (feed.confidence !== undefined) {
128
- const v = feed.confidence === null ? 0n : feed.confidence;
129
- parts.push(encodeFeedProperty(PROP_ID.Confidence, i64Le(v)));
130
- }
131
- if (feed.fundingRate !== undefined) {
132
- if (feed.fundingRate === null) {
133
- parts.push(encodeFeedProperty(PROP_ID.FundingRate, u8(0)));
134
- } else {
135
- parts.push(
136
- encodeFeedProperty(
137
- PROP_ID.FundingRate,
138
- concat(u8(1), i64Le(feed.fundingRate)),
139
- ),
140
- );
141
- }
142
- }
143
- if (feed.fundingTimestamp !== undefined) {
144
- if (feed.fundingTimestamp === null) {
145
- parts.push(encodeFeedProperty(PROP_ID.FundingTimestamp, u8(0)));
146
- } else {
147
- parts.push(
148
- encodeFeedProperty(
149
- PROP_ID.FundingTimestamp,
150
- concat(u8(1), u64Le(feed.fundingTimestamp)),
151
- ),
152
- );
153
- }
154
- }
155
- if (feed.fundingRateInterval !== undefined) {
156
- if (feed.fundingRateInterval === null) {
157
- parts.push(encodeFeedProperty(PROP_ID.FundingRateInterval, u8(0)));
158
- } else {
159
- parts.push(
160
- encodeFeedProperty(
161
- PROP_ID.FundingRateInterval,
162
- concat(u8(1), u64Le(feed.fundingRateInterval)),
163
- ),
164
- );
165
- }
166
- }
167
- if (feed.marketSession !== undefined) {
168
- const idx = MARKET_SESSION_ORDER.indexOf(feed.marketSession);
169
- if (idx < 0) throw new RangeError('Invalid marketSession');
170
- parts.push(encodeFeedProperty(PROP_ID.MarketSession, u16Le(idx)));
171
- }
172
- if (feed.emaPrice !== undefined) {
173
- const v = feed.emaPrice === null ? 0n : feed.emaPrice;
174
- parts.push(encodeFeedProperty(PROP_ID.EmaPrice, i64Le(v)));
175
- }
176
- if (feed.emaConfidence !== undefined) {
177
- const v = feed.emaConfidence === null ? 0n : feed.emaConfidence;
178
- parts.push(encodeFeedProperty(PROP_ID.EmaConfidence, i64Le(v)));
179
- }
180
- if (feed.feedUpdateTimestamp !== undefined) {
181
- if (feed.feedUpdateTimestamp === null) {
182
- parts.push(encodeFeedProperty(PROP_ID.FeedUpdateTimestamp, u8(0)));
183
- } else {
184
- parts.push(
185
- encodeFeedProperty(
186
- PROP_ID.FeedUpdateTimestamp,
187
- concat(u8(1), u64Le(feed.feedUpdateTimestamp)),
188
- ),
189
- );
190
- }
191
- }
192
-
193
- const properties = concat(...parts);
194
- if (parts.length > 255)
195
- throw new RangeError('Feed has more than 255 properties');
196
- return concat(
197
- u32Le(feed.feedId),
198
- u8(parts.length), // number of properties (parser.repeat count), not byte length
199
- properties,
200
- );
201
- }
202
-
203
- /**
204
- * Encode a PriceUpdate to the binary payload format consumed by the on-chain parser.
205
- * This is the payload that goes inside a PythMessage.
206
- */
207
- export function encodePriceUpdate(update: PriceUpdate): Uint8Array {
208
- if (update.priceFeeds.length > 255) {
209
- throw new RangeError('At most 255 feeds allowed');
210
- }
211
- const feeds: Feed[] = update.priceFeeds.map(toFeed);
212
- const feedBytes = feeds.map(encodeFeed);
213
- return concat(
214
- PRICE_UPDATE_MAGIC,
215
- u64Le(BigInt(update.timestampUs)),
216
- u8(update.channelId),
217
- u8(feeds.length),
218
- ...feedBytes,
219
- );
220
- }
221
-
222
- /**
223
- * Encode a full Pyth message (Solana format): magic + signature + key + payload length + payload.
224
- * Use this when you already have a signed payload (e.g. from a Pyth API or after signing locally).
225
- */
226
- export function encodePythMessage(parts: PythMessageParts): Uint8Array {
227
- if (parts.signature.length !== 64) {
228
- throw new RangeError('signature must be 64 bytes');
229
- }
230
- if (parts.publicKey.length !== 32) {
231
- throw new RangeError('publicKey must be 32 bytes');
232
- }
233
- if (parts.payload.length > 0xffff) {
234
- throw new RangeError('payload length exceeds u16 max');
235
- }
236
- return concat(
237
- SOLANA_FORMAT_MAGIC,
238
- parts.signature,
239
- parts.publicKey,
240
- u16Le(parts.payload.length),
241
- parts.payload,
242
- );
243
- }
244
-
245
- /**
246
- * Encode a PythMessage whose payload is a PriceUpdate.
247
- * Signs the payload with the given secret key (32-byte Ed25519 seed).
248
- * Returns the full message bytes (hex-friendly).
249
- */
250
- export async function encodeSignedPythMessage(
251
- update: PriceUpdate,
252
- secretKey: Uint8Array,
253
- ): Promise<Uint8Array> {
254
- if (secretKey.length !== 32) {
255
- throw new RangeError('secretKey must be 32 bytes (Ed25519 seed)');
256
- }
257
- const noble = await import('@noble/ed25519');
258
- const payload = encodePriceUpdate(update);
259
- const publicKey = await noble.getPublicKeyAsync(secretKey);
260
- const signature = await noble.signAsync(payload, secretKey);
261
- return encodePythMessage({ signature, publicKey, payload });
262
- }
@@ -1,14 +0,0 @@
1
- export type {
2
- Feed,
3
- MarketSession,
4
- PriceUpdate,
5
- PythMessageParts,
6
- } from './types.js';
7
- export { decodePriceUpdate, decodePythMessage } from './decode.js';
8
- export {
9
- encodePriceUpdate,
10
- encodePythMessage,
11
- encodeSignedPythMessage,
12
- PRICE_UPDATE_MAGIC,
13
- SOLANA_FORMAT_MAGIC,
14
- } from './encode.js';