@reflectmoney/oracle.ts 1.0.0 → 2.0.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/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @reflectmoney/oracle.ts
2
+
3
+ TypeScript SDK for Doppler, the efficient oracle program implemented by [Blueshift](https://blueshift.gg), used by Reflect.
4
+
5
+ ## About
6
+
7
+ Reflect uses [Doppler](https://github.com/blueshift-gg/doppler) as its oracle solution, enabling oracle updates with just **21 compute units** per call - one of the most efficient implementations on Solana.
8
+
9
+ **Program ID:** `PRicevBH6BaeaE8qmrxrwGBZ5hSZ9vjBNue5Ygot1ML`
10
+
11
+ ## Installation
12
+
13
+ With NPM:
14
+ ```bash
15
+ npm install @reflectmoney/oracle.ts
16
+ ```
17
+
18
+ With Yarn:
19
+ ```bash
20
+ yarn add @reflectmoney/oracle.ts
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Initialize Doppler
26
+
27
+ ```typescript
28
+ import { Doppler, U8Array8Serializer, createPricePayload } from "@reflectmoney/oracle.ts";
29
+ import { Connection, Keypair } from "@solana/web3.js";
30
+
31
+ const connection = new Connection("https://api.mainnet-beta.solana.com");
32
+ const admin = Keypair.fromSecretKey(/* admin keypair */);
33
+
34
+ const doppler = new Doppler(connection, admin);
35
+ ```
36
+
37
+ ### Update an Oracle
38
+
39
+ ```typescript
40
+ import { PublicKey } from "@solana/web3.js";
41
+
42
+ const oraclePublicKey = new PublicKey("ORACLE_ADDRESS");
43
+
44
+ // Create a price payload (8 bytes representing a u64 value)
45
+ const pricePayload = createPricePayload(BigInt(1_000_000)); // 1 USDC
46
+
47
+ await doppler.updateOracle(
48
+ oraclePublicKey,
49
+ {
50
+ slot: BigInt(Date.now()),
51
+ payload: pricePayload,
52
+ },
53
+ new U8Array8Serializer(),
54
+ );
55
+ ```
56
+
57
+ ### Fetch Oracle Data
58
+
59
+ ```typescript
60
+ import { readPriceFromPayload } from "@reflectmoney/oracle.ts";
61
+
62
+ const oracleData = await doppler.fetchOracle(
63
+ oraclePublicKey,
64
+ new U8Array8Serializer(),
65
+ );
66
+
67
+ if (oracleData) {
68
+ console.log("Slot:", oracleData.slot);
69
+
70
+ // Extract price from the 8-byte payload
71
+ const price = readPriceFromPayload(oracleData.payload);
72
+ console.log("Price:", price);
73
+ }
74
+ // Output:
75
+ // Slot: 1728662400000n
76
+ // Price: 1000000n
77
+ ```
78
+
79
+ ### Create an Oracle Account
80
+
81
+ ```typescript
82
+ const oracleAccount = await doppler.createOracleAccount(
83
+ "my-oracle-seed",
84
+ new U8Array8Serializer(),
85
+ {
86
+ slot: 0n,
87
+ payload: createPricePayload(BigInt(1_000_000)),
88
+ }
89
+ );
90
+ ```
91
+
92
+ ## Links
93
+
94
+ - [GitHub Repository](https://github.com/palindrome-eng/doppler)
95
+ - [Reflect](https://reflect.money)
96
+
97
+ ## License
98
+
99
+ MIT
100
+
package/dist/index.d.ts CHANGED
@@ -3,10 +3,10 @@ import { Buffer } from 'buffer';
3
3
  export declare const DOPPLER_PROGRAM_ID: PublicKey;
4
4
  export declare const ADMIN_PUBKEY: PublicKey;
5
5
  /**
6
- * Generic Oracle data structure
6
+ * Generic Oracle data structure matching Rust implementation
7
7
  */
8
8
  export interface Oracle<T> {
9
- sequence: bigint;
9
+ slot: bigint;
10
10
  payload: T;
11
11
  }
12
12
  /**
@@ -18,27 +18,22 @@ export interface PayloadSerializer<T> {
18
18
  size(): number;
19
19
  }
20
20
  /**
21
- * Built-in serializer for u64 payloads (price feeds)
21
+ * Built-in serializer for [u8; 8] payloads (used for price feeds)
22
+ * The payload is simply 8 bytes representing data in little-endian format
22
23
  */
23
- export declare class U64Serializer implements PayloadSerializer<bigint> {
24
- serialize(payload: bigint): Buffer;
25
- deserialize(buffer: Buffer): bigint;
24
+ export declare class U8Array8Serializer implements PayloadSerializer<Buffer> {
25
+ serialize(payload: Buffer): Buffer;
26
+ deserialize(buffer: Buffer): Buffer;
26
27
  size(): number;
27
28
  }
28
29
  /**
29
- * Price Feed structure matching the Rust implementation
30
+ * Helper function to create a [u8; 8] payload from a bigint price value
30
31
  */
31
- export interface PriceFeed {
32
- price: bigint;
33
- }
32
+ export declare function createPricePayload(price: bigint): Buffer;
34
33
  /**
35
- * Serializer for PriceFeed payloads
34
+ * Helper function to read a price value from a [u8; 8] payload
36
35
  */
37
- export declare class PriceFeedSerializer implements PayloadSerializer<PriceFeed> {
38
- serialize(payload: PriceFeed): Buffer;
39
- deserialize(buffer: Buffer): PriceFeed;
40
- size(): number;
41
- }
36
+ export declare function readPriceFromPayload(payload: Buffer): bigint;
42
37
  /**
43
38
  * Transaction builder for Doppler oracle updates
44
39
  */
package/dist/index.js CHANGED
@@ -9,7 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.Doppler = exports.TransactionBuilder = exports.PriceFeedSerializer = exports.U64Serializer = exports.ADMIN_PUBKEY = exports.DOPPLER_PROGRAM_ID = void 0;
12
+ exports.Doppler = exports.TransactionBuilder = exports.U8Array8Serializer = exports.ADMIN_PUBKEY = exports.DOPPLER_PROGRAM_ID = void 0;
13
+ exports.createPricePayload = createPricePayload;
14
+ exports.readPriceFromPayload = readPriceFromPayload;
13
15
  const web3_js_1 = require("@solana/web3.js");
14
16
  const buffer_1 = require("buffer");
15
17
  const compute_budget_1 = require("@solana-program/compute-budget");
@@ -28,41 +30,44 @@ const COMPUTE_BUDGET_DATA_LIMIT_SIZE = 5;
28
30
  const COMPUTE_BUDGET_PROGRAM_SIZE = 22;
29
31
  const ORACLE_PROGRAM_SIZE = 36;
30
32
  /**
31
- * Built-in serializer for u64 payloads (price feeds)
33
+ * Built-in serializer for [u8; 8] payloads (used for price feeds)
34
+ * The payload is simply 8 bytes representing data in little-endian format
32
35
  */
33
- class U64Serializer {
36
+ class U8Array8Serializer {
34
37
  serialize(payload) {
35
- const buf = buffer_1.Buffer.alloc(8);
36
- buf.writeBigUInt64LE(payload);
37
- return buf;
38
+ if (payload.length !== 8) {
39
+ throw new Error('Payload must be exactly 8 bytes');
40
+ }
41
+ return payload;
38
42
  }
39
43
  deserialize(buffer) {
40
- return buffer.readBigUInt64LE(0);
44
+ if (buffer.length < 8) {
45
+ throw new Error('Buffer must be at least 8 bytes');
46
+ }
47
+ return buffer.subarray(0, 8);
41
48
  }
42
49
  size() {
43
50
  return 8;
44
51
  }
45
52
  }
46
- exports.U64Serializer = U64Serializer;
53
+ exports.U8Array8Serializer = U8Array8Serializer;
47
54
  /**
48
- * Serializer for PriceFeed payloads
55
+ * Helper function to create a [u8; 8] payload from a bigint price value
49
56
  */
50
- class PriceFeedSerializer {
51
- serialize(payload) {
52
- const buf = buffer_1.Buffer.alloc(8);
53
- buf.writeBigUInt64LE(payload.price);
54
- return buf;
55
- }
56
- deserialize(buffer) {
57
- return {
58
- price: buffer.readBigUInt64LE(0),
59
- };
60
- }
61
- size() {
62
- return 8;
57
+ function createPricePayload(price) {
58
+ const buf = buffer_1.Buffer.alloc(8);
59
+ buf.writeBigUInt64LE(price);
60
+ return buf;
61
+ }
62
+ /**
63
+ * Helper function to read a price value from a [u8; 8] payload
64
+ */
65
+ function readPriceFromPayload(payload) {
66
+ if (payload.length < 8) {
67
+ throw new Error('Payload must be at least 8 bytes');
63
68
  }
69
+ return payload.readBigUInt64LE(0);
64
70
  }
65
- exports.PriceFeedSerializer = PriceFeedSerializer;
66
71
  /**
67
72
  * Transaction builder for Doppler oracle updates
68
73
  */
@@ -83,7 +88,7 @@ class TransactionBuilder {
83
88
  addOracleUpdate(oraclePubkey, oracle, serializer) {
84
89
  const instruction = this.createUpdateInstruction(oraclePubkey, oracle, serializer);
85
90
  const payloadSize = serializer.size();
86
- const oracleSize = 8 + payloadSize; // sequence + payload
91
+ const oracleSize = 8 + payloadSize; // slot + payload
87
92
  this.computeUnits +=
88
93
  SEQUENCE_CHECK_CU +
89
94
  ADMIN_VERIFICATION_CU +
@@ -149,15 +154,20 @@ class TransactionBuilder {
149
154
  isSigner: false,
150
155
  isWritable: true,
151
156
  },
157
+ {
158
+ pubkey: web3_js_1.SYSVAR_CLOCK_PUBKEY,
159
+ isSigner: false,
160
+ isWritable: false,
161
+ },
152
162
  ],
153
163
  data,
154
164
  });
155
165
  }
156
166
  serializeOracle(oracle, serializer) {
157
- const sequenceBuffer = buffer_1.Buffer.alloc(8);
158
- sequenceBuffer.writeBigUInt64LE(oracle.sequence);
167
+ const slotBuffer = buffer_1.Buffer.alloc(8);
168
+ slotBuffer.writeBigUInt64LE(oracle.slot);
159
169
  const payloadBuffer = serializer.serialize(oracle.payload);
160
- return buffer_1.Buffer.concat([sequenceBuffer, payloadBuffer]);
170
+ return buffer_1.Buffer.concat([slotBuffer, payloadBuffer]);
161
171
  }
162
172
  }
163
173
  exports.TransactionBuilder = TransactionBuilder;
@@ -201,10 +211,10 @@ class Doppler {
201
211
  if (data.length < expectedSize) {
202
212
  throw new Error(`Invalid oracle data size. Expected at least ${expectedSize}, got ${data.length}`);
203
213
  }
204
- const sequence = data.readBigUInt64LE(0);
214
+ const slot = data.readBigUInt64LE(0);
205
215
  const payloadBuffer = data.subarray(8, 8 + serializer.size());
206
216
  const payload = serializer.deserialize(payloadBuffer);
207
- return { sequence, payload };
217
+ return { slot, payload };
208
218
  }
209
219
  /**
210
220
  * Create an oracle account with a seed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reflectmoney/oracle.ts",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "type": "commonjs",
5
5
  "author": "L0STE, stablecoinjesus @ Palindrome Engineering",
6
6
  "repository": {