@reflectmoney/oracle.ts 1.0.1 → 2.1.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 +23 -10
- package/dist/index.d.ts +15 -21
- package/dist/index.js +44 -40
- package/package.json +1 -1
package/README.md
CHANGED
@@ -25,7 +25,7 @@ yarn add @reflectmoney/oracle.ts
|
|
25
25
|
### Initialize Doppler
|
26
26
|
|
27
27
|
```typescript
|
28
|
-
import { Doppler,
|
28
|
+
import { Doppler, U8Array8Serializer, createPricePayload } from "@reflectmoney/oracle.ts";
|
29
29
|
import { Connection, Keypair } from "@solana/web3.js";
|
30
30
|
|
31
31
|
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
@@ -41,26 +41,39 @@ import { PublicKey } from "@solana/web3.js";
|
|
41
41
|
|
42
42
|
const oraclePublicKey = new PublicKey("ORACLE_ADDRESS");
|
43
43
|
|
44
|
+
// Create a price payload (8 bytes representing a u64 value)
|
45
|
+
const pricePayload = createPricePayload(BigInt(1_000_000)); // 1 USDC
|
46
|
+
|
44
47
|
await doppler.updateOracle(
|
45
48
|
oraclePublicKey,
|
46
49
|
{
|
47
|
-
|
48
|
-
|
50
|
+
slot: BigInt(Date.now()),
|
51
|
+
payload: pricePayload,
|
49
52
|
},
|
50
|
-
new
|
53
|
+
new U8Array8Serializer(),
|
51
54
|
);
|
52
55
|
```
|
53
56
|
|
54
57
|
### Fetch Oracle Data
|
55
58
|
|
56
59
|
```typescript
|
60
|
+
import { readPriceFromPayload } from "@reflectmoney/oracle.ts";
|
61
|
+
|
57
62
|
const oracleData = await doppler.fetchOracle(
|
58
63
|
oraclePublicKey,
|
59
|
-
new
|
64
|
+
new U8Array8Serializer(),
|
60
65
|
);
|
61
66
|
|
62
|
-
|
63
|
-
|
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
|
64
77
|
```
|
65
78
|
|
66
79
|
### Create an Oracle Account
|
@@ -68,10 +81,10 @@ console.log(oracleData);
|
|
68
81
|
```typescript
|
69
82
|
const oracleAccount = await doppler.createOracleAccount(
|
70
83
|
"my-oracle-seed",
|
71
|
-
new
|
84
|
+
new U8Array8Serializer(),
|
72
85
|
{
|
73
|
-
|
74
|
-
|
86
|
+
slot: 0n,
|
87
|
+
payload: createPricePayload(BigInt(1_000_000)),
|
75
88
|
}
|
76
89
|
);
|
77
90
|
```
|
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
|
-
|
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
|
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
|
24
|
-
serialize(payload:
|
25
|
-
deserialize(buffer: Buffer):
|
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
|
-
*
|
30
|
+
* Helper function to create a [u8; 8] payload from a bigint price value
|
30
31
|
*/
|
31
|
-
export
|
32
|
-
price: bigint;
|
33
|
-
}
|
32
|
+
export declare function createPricePayload(price: bigint): Buffer;
|
34
33
|
/**
|
35
|
-
*
|
34
|
+
* Helper function to read a price value from a [u8; 8] payload
|
36
35
|
*/
|
37
|
-
export declare
|
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
|
*/
|
@@ -52,7 +47,7 @@ export declare class TransactionBuilder {
|
|
52
47
|
/**
|
53
48
|
* Add an oracle update instruction to the transaction
|
54
49
|
*/
|
55
|
-
addOracleUpdate<T>(oraclePubkey: PublicKey,
|
50
|
+
addOracleUpdate<T>(oraclePubkey: PublicKey, payload: T, serializer: PayloadSerializer<T>): this;
|
56
51
|
/**
|
57
52
|
* Set the compute unit price in micro-lamports
|
58
53
|
*/
|
@@ -62,7 +57,6 @@ export declare class TransactionBuilder {
|
|
62
57
|
*/
|
63
58
|
build(recentBlockhash: string): Transaction;
|
64
59
|
private createUpdateInstruction;
|
65
|
-
private serializeOracle;
|
66
60
|
}
|
67
61
|
/**
|
68
62
|
* Main Doppler class for interacting with oracle accounts
|
@@ -86,17 +80,17 @@ export declare class Doppler {
|
|
86
80
|
/**
|
87
81
|
* Create an oracle account with a seed
|
88
82
|
*/
|
89
|
-
createOracleAccount<T>(seed: string, serializer: PayloadSerializer<T
|
83
|
+
createOracleAccount<T>(seed: string, serializer: PayloadSerializer<T>): Promise<PublicKey>;
|
90
84
|
/**
|
91
85
|
* Update a single oracle account
|
92
86
|
*/
|
93
|
-
updateOracle<T>(oraclePubkey: PublicKey,
|
87
|
+
updateOracle<T>(oraclePubkey: PublicKey, payload: T, serializer: PayloadSerializer<T>, unitPrice?: bigint): Promise<string>;
|
94
88
|
/**
|
95
89
|
* Update multiple oracle accounts in a single transaction
|
96
90
|
*/
|
97
91
|
updateMultipleOracles<T>(updates: Array<{
|
98
92
|
oraclePubkey: PublicKey;
|
99
|
-
|
93
|
+
payload: T;
|
100
94
|
serializer: PayloadSerializer<T>;
|
101
95
|
}>, unitPrice?: bigint): Promise<string>;
|
102
96
|
/**
|
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.
|
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
|
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
|
36
|
+
class U8Array8Serializer {
|
34
37
|
serialize(payload) {
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
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.
|
53
|
+
exports.U8Array8Serializer = U8Array8Serializer;
|
47
54
|
/**
|
48
|
-
*
|
55
|
+
* Helper function to create a [u8; 8] payload from a bigint price value
|
49
56
|
*/
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
*/
|
@@ -80,10 +85,10 @@ class TransactionBuilder {
|
|
80
85
|
/**
|
81
86
|
* Add an oracle update instruction to the transaction
|
82
87
|
*/
|
83
|
-
addOracleUpdate(oraclePubkey,
|
84
|
-
const instruction = this.createUpdateInstruction(oraclePubkey,
|
88
|
+
addOracleUpdate(oraclePubkey, payload, serializer) {
|
89
|
+
const instruction = this.createUpdateInstruction(oraclePubkey, payload, serializer);
|
85
90
|
const payloadSize = serializer.size();
|
86
|
-
const oracleSize = 8 + payloadSize; //
|
91
|
+
const oracleSize = 8 + payloadSize; // slot + payload
|
87
92
|
this.computeUnits +=
|
88
93
|
SEQUENCE_CHECK_CU +
|
89
94
|
ADMIN_VERIFICATION_CU +
|
@@ -134,8 +139,8 @@ class TransactionBuilder {
|
|
134
139
|
transaction.sign(this.admin);
|
135
140
|
return transaction;
|
136
141
|
}
|
137
|
-
createUpdateInstruction(oraclePubkey,
|
138
|
-
const data =
|
142
|
+
createUpdateInstruction(oraclePubkey, payload, serializer) {
|
143
|
+
const data = serializer.serialize(payload);
|
139
144
|
return new web3_js_1.TransactionInstruction({
|
140
145
|
programId: exports.DOPPLER_PROGRAM_ID,
|
141
146
|
keys: [
|
@@ -149,16 +154,15 @@ 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
|
-
serializeOracle(oracle, serializer) {
|
157
|
-
const sequenceBuffer = buffer_1.Buffer.alloc(8);
|
158
|
-
sequenceBuffer.writeBigUInt64LE(oracle.sequence);
|
159
|
-
const payloadBuffer = serializer.serialize(oracle.payload);
|
160
|
-
return buffer_1.Buffer.concat([sequenceBuffer, payloadBuffer]);
|
161
|
-
}
|
162
166
|
}
|
163
167
|
exports.TransactionBuilder = TransactionBuilder;
|
164
168
|
/**
|
@@ -201,15 +205,15 @@ class Doppler {
|
|
201
205
|
if (data.length < expectedSize) {
|
202
206
|
throw new Error(`Invalid oracle data size. Expected at least ${expectedSize}, got ${data.length}`);
|
203
207
|
}
|
204
|
-
const
|
208
|
+
const slot = data.readBigUInt64LE(0);
|
205
209
|
const payloadBuffer = data.subarray(8, 8 + serializer.size());
|
206
210
|
const payload = serializer.deserialize(payloadBuffer);
|
207
|
-
return {
|
211
|
+
return { slot, payload };
|
208
212
|
}
|
209
213
|
/**
|
210
214
|
* Create an oracle account with a seed
|
211
215
|
*/
|
212
|
-
createOracleAccount(seed, serializer
|
216
|
+
createOracleAccount(seed, serializer) {
|
213
217
|
return __awaiter(this, void 0, void 0, function* () {
|
214
218
|
const oracleSize = 8 + serializer.size();
|
215
219
|
const lamports = yield this.connection.getMinimumBalanceForRentExemption(oracleSize);
|
@@ -237,10 +241,10 @@ class Doppler {
|
|
237
241
|
/**
|
238
242
|
* Update a single oracle account
|
239
243
|
*/
|
240
|
-
updateOracle(oraclePubkey,
|
244
|
+
updateOracle(oraclePubkey, payload, serializer, unitPrice) {
|
241
245
|
return __awaiter(this, void 0, void 0, function* () {
|
242
246
|
const recentBlockhash = yield this.connection.getLatestBlockhash();
|
243
|
-
let builder = this.createTransactionBuilder().addOracleUpdate(oraclePubkey,
|
247
|
+
let builder = this.createTransactionBuilder().addOracleUpdate(oraclePubkey, payload, serializer);
|
244
248
|
if (unitPrice !== undefined) {
|
245
249
|
builder = builder.withUnitPrice(unitPrice);
|
246
250
|
}
|
@@ -257,7 +261,7 @@ class Doppler {
|
|
257
261
|
const recentBlockhash = yield this.connection.getLatestBlockhash();
|
258
262
|
let builder = this.createTransactionBuilder();
|
259
263
|
for (const update of updates) {
|
260
|
-
builder = builder.addOracleUpdate(update.oraclePubkey, update.
|
264
|
+
builder = builder.addOracleUpdate(update.oraclePubkey, update.payload, update.serializer);
|
261
265
|
}
|
262
266
|
if (unitPrice !== undefined) {
|
263
267
|
builder = builder.withUnitPrice(unitPrice);
|