@revealui/services 0.1.0 → 0.2.1
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/dist/api/handlers/subscription-handlers.d.ts +5 -1
- package/dist/api/handlers/subscription-handlers.d.ts.map +1 -1
- package/dist/api/handlers/subscription-handlers.js +5 -1
- package/dist/api/handlers/subscription-handlers.js.map +1 -1
- package/dist/api/webhooks/index.d.ts +10 -0
- package/dist/api/webhooks/index.d.ts.map +1 -1
- package/dist/api/webhooks/index.js +10 -0
- package/dist/api/webhooks/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/revealcoin/__tests__/client.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/client.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/client.test.js +207 -0
- package/dist/revealcoin/__tests__/client.test.js.map +1 -0
- package/dist/revealcoin/__tests__/config.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/config.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/config.test.js +91 -0
- package/dist/revealcoin/__tests__/config.test.js.map +1 -0
- package/dist/revealcoin/__tests__/oracle.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/oracle.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/oracle.test.js +238 -0
- package/dist/revealcoin/__tests__/oracle.test.js.map +1 -0
- package/dist/revealcoin/__tests__/safeguards.test.d.ts +2 -0
- package/dist/revealcoin/__tests__/safeguards.test.d.ts.map +1 -0
- package/dist/revealcoin/__tests__/safeguards.test.js +571 -0
- package/dist/revealcoin/__tests__/safeguards.test.js.map +1 -0
- package/dist/revealcoin/client.d.ts +51 -0
- package/dist/revealcoin/client.d.ts.map +1 -0
- package/dist/revealcoin/client.js +211 -0
- package/dist/revealcoin/client.js.map +1 -0
- package/dist/revealcoin/config.d.ts +32 -0
- package/dist/revealcoin/config.d.ts.map +1 -0
- package/dist/revealcoin/config.js +54 -0
- package/dist/revealcoin/config.js.map +1 -0
- package/dist/revealcoin/index.d.ts +5 -0
- package/dist/revealcoin/index.d.ts.map +1 -0
- package/dist/revealcoin/index.js +5 -0
- package/dist/revealcoin/index.js.map +1 -0
- package/dist/revealcoin/oracle.d.ts +81 -0
- package/dist/revealcoin/oracle.d.ts.map +1 -0
- package/dist/revealcoin/oracle.js +211 -0
- package/dist/revealcoin/oracle.js.map +1 -0
- package/dist/revealcoin/safeguards.d.ts +92 -0
- package/dist/revealcoin/safeguards.d.ts.map +1 -0
- package/dist/revealcoin/safeguards.js +240 -0
- package/dist/revealcoin/safeguards.js.map +1 -0
- package/package.json +9 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/revealcoin/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAgInE,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA4ChF;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA6D5D;AAMD,eAAO,MAAM,sBAAsB,kBAAuB,CAAC;AAC3D,eAAO,MAAM,wBAAwB;;;;CAAyB,CAAC;AAC/D,eAAO,MAAM,cAAc;;;;CAAe,CAAC;AAC3C,eAAO,MAAM,qBAAqB,QAAO,OAAO,CAAC,IAAI,CAAiC,CAAC;AACvF,eAAO,MAAM,iBAAiB,QAAO,IAGpC,CAAC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RevealCoin RPC Client
|
|
3
|
+
*
|
|
4
|
+
* Provides balance queries and payment verification for RevealCoin (RVUI)
|
|
5
|
+
* on the Solana blockchain. Uses circuit breaker + retry pattern mirroring
|
|
6
|
+
* the Stripe client in packages/services/src/stripe/stripeClient.ts.
|
|
7
|
+
*/
|
|
8
|
+
import { RVUI_MINT_ADDRESSES, RVUI_TOKEN_CONFIG, RVUI_TOKEN_PROGRAM, } from '@revealui/contracts';
|
|
9
|
+
import { createLogger } from '@revealui/core/observability/logger';
|
|
10
|
+
import { address, createSolanaRpc, signature } from '@solana/kit';
|
|
11
|
+
import { getRevealCoinConfig, resolveRpcUrl } from './config.js';
|
|
12
|
+
import { DbCircuitBreaker } from '../stripe/db-circuit-breaker.js';
|
|
13
|
+
const logger = createLogger({ service: 'RevealCoin' });
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Circuit Breaker (DB-backed, shared across API instances)
|
|
16
|
+
// =============================================================================
|
|
17
|
+
const CIRCUIT_BREAKER_CONFIG = {
|
|
18
|
+
failureThreshold: 5,
|
|
19
|
+
resetTimeout: 30_000,
|
|
20
|
+
successThreshold: 2,
|
|
21
|
+
};
|
|
22
|
+
const solanaCircuitBreaker = new DbCircuitBreaker('solana-rpc', {
|
|
23
|
+
failureThreshold: CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
24
|
+
successThreshold: CIRCUIT_BREAKER_CONFIG.successThreshold,
|
|
25
|
+
resetTimeout: CIRCUIT_BREAKER_CONFIG.resetTimeout,
|
|
26
|
+
});
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Retry Configuration
|
|
29
|
+
// =============================================================================
|
|
30
|
+
const RETRY_CONFIG = {
|
|
31
|
+
maxAttempts: 3,
|
|
32
|
+
backoff: [200, 500, 1000],
|
|
33
|
+
timeout: 15_000,
|
|
34
|
+
};
|
|
35
|
+
function sleep(ms) {
|
|
36
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
|
+
}
|
|
38
|
+
function withTimeout(promise, timeoutMs) {
|
|
39
|
+
return Promise.race([
|
|
40
|
+
promise,
|
|
41
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Solana RPC timed out after ${timeoutMs}ms`)), timeoutMs)),
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// Resilient RPC Wrapper
|
|
46
|
+
// =============================================================================
|
|
47
|
+
async function callWithResilience(operation, operationName) {
|
|
48
|
+
if (await solanaCircuitBreaker.isOpen()) {
|
|
49
|
+
logger.error('Solana RPC circuit breaker is OPEN', undefined, {
|
|
50
|
+
operation: operationName,
|
|
51
|
+
state: 'open',
|
|
52
|
+
});
|
|
53
|
+
throw new Error('Solana RPC circuit breaker is OPEN. Service unavailable.');
|
|
54
|
+
}
|
|
55
|
+
let lastError;
|
|
56
|
+
for (let attempt = 0; attempt < RETRY_CONFIG.maxAttempts; attempt++) {
|
|
57
|
+
try {
|
|
58
|
+
const result = await withTimeout(operation(), RETRY_CONFIG.timeout);
|
|
59
|
+
await solanaCircuitBreaker.recordSuccess();
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
lastError = error;
|
|
64
|
+
const isRetryable = error instanceof Error &&
|
|
65
|
+
(error.message.includes('timeout') ||
|
|
66
|
+
error.message.includes('ECONNREFUSED') ||
|
|
67
|
+
error.message.includes('ETIMEDOUT') ||
|
|
68
|
+
error.message.includes('429') ||
|
|
69
|
+
error.message.includes('503'));
|
|
70
|
+
if (!isRetryable) {
|
|
71
|
+
await solanaCircuitBreaker.recordFailure();
|
|
72
|
+
logger.error(`${operationName} failed (non-retryable)`, error instanceof Error ? error : new Error(String(error)), { operation: operationName, attempt: attempt + 1 });
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
logger.warn(`${operationName} failed (retryable), retrying...`, {
|
|
76
|
+
operation: operationName,
|
|
77
|
+
attempt: attempt + 1,
|
|
78
|
+
error: error instanceof Error ? error.message : String(error),
|
|
79
|
+
});
|
|
80
|
+
if (attempt < RETRY_CONFIG.maxAttempts - 1) {
|
|
81
|
+
const backoffMs = RETRY_CONFIG.backoff[attempt] ??
|
|
82
|
+
RETRY_CONFIG.backoff[RETRY_CONFIG.backoff.length - 1] ??
|
|
83
|
+
1000;
|
|
84
|
+
await sleep(backoffMs);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
await solanaCircuitBreaker.recordFailure();
|
|
89
|
+
throw lastError instanceof Error
|
|
90
|
+
? new Error(`${operationName} failed after ${RETRY_CONFIG.maxAttempts} attempts: ${lastError.message}`)
|
|
91
|
+
: new Error(`${operationName} failed after ${RETRY_CONFIG.maxAttempts} attempts`);
|
|
92
|
+
}
|
|
93
|
+
// =============================================================================
|
|
94
|
+
// Connection Management
|
|
95
|
+
// =============================================================================
|
|
96
|
+
let _rpc = null;
|
|
97
|
+
let _rpcUrl = null;
|
|
98
|
+
function getRpc() {
|
|
99
|
+
const rpcUrl = resolveRpcUrl();
|
|
100
|
+
if (_rpc && _rpcUrl === rpcUrl)
|
|
101
|
+
return _rpc;
|
|
102
|
+
_rpc = createSolanaRpc(rpcUrl);
|
|
103
|
+
_rpcUrl = rpcUrl;
|
|
104
|
+
return _rpc;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the RVUI balance for a wallet address.
|
|
108
|
+
*
|
|
109
|
+
* Queries the Token-2022 Associated Token Account for the RVUI mint.
|
|
110
|
+
* Returns zero balance if the ATA does not exist (wallet has never held RVUI).
|
|
111
|
+
*/
|
|
112
|
+
export async function getRvuiBalance(walletAddress) {
|
|
113
|
+
return callWithResilience(async () => {
|
|
114
|
+
const rpc = getRpc();
|
|
115
|
+
const config = getRevealCoinConfig();
|
|
116
|
+
const mintAddress = RVUI_MINT_ADDRESSES[config.network];
|
|
117
|
+
if (!mintAddress) {
|
|
118
|
+
throw new Error(`RVUI not deployed on ${config.network}`);
|
|
119
|
+
}
|
|
120
|
+
const wallet = address(walletAddress);
|
|
121
|
+
const mint = address(mintAddress);
|
|
122
|
+
const response = await rpc
|
|
123
|
+
.getTokenAccountsByOwner(wallet, { mint }, { encoding: 'jsonParsed', commitment: config.queryCommitment })
|
|
124
|
+
.send();
|
|
125
|
+
if (response.value.length === 0) {
|
|
126
|
+
return { raw: 0n, formatted: '0', uiAmount: 0 };
|
|
127
|
+
}
|
|
128
|
+
const firstAccount = response.value[0];
|
|
129
|
+
if (!firstAccount) {
|
|
130
|
+
return { raw: 0n, formatted: '0', uiAmount: 0 };
|
|
131
|
+
}
|
|
132
|
+
const accountData = firstAccount.account.data;
|
|
133
|
+
const raw = BigInt(accountData.parsed.info.tokenAmount.amount);
|
|
134
|
+
const divisor = 10 ** RVUI_TOKEN_CONFIG.decimals;
|
|
135
|
+
const uiAmount = Number(raw) / divisor;
|
|
136
|
+
return {
|
|
137
|
+
raw,
|
|
138
|
+
formatted: uiAmount.toLocaleString(undefined, {
|
|
139
|
+
minimumFractionDigits: 0,
|
|
140
|
+
maximumFractionDigits: RVUI_TOKEN_CONFIG.decimals,
|
|
141
|
+
}),
|
|
142
|
+
uiAmount,
|
|
143
|
+
};
|
|
144
|
+
}, 'getRvuiBalance');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Verify an RVUI payment transaction on-chain.
|
|
148
|
+
*
|
|
149
|
+
* Confirms that a Solana transaction contains a Token-2022 transfer of
|
|
150
|
+
* the correct amount to the expected recipient for the RVUI mint.
|
|
151
|
+
*
|
|
152
|
+
* Uses `finalized` commitment to prevent rollback exploits.
|
|
153
|
+
*/
|
|
154
|
+
export async function verifyRvuiPayment(txSignature, expectedAmountRaw, expectedRecipient) {
|
|
155
|
+
return callWithResilience(async () => {
|
|
156
|
+
const rpc = getRpc();
|
|
157
|
+
const config = getRevealCoinConfig();
|
|
158
|
+
const mintAddress = RVUI_MINT_ADDRESSES[config.network];
|
|
159
|
+
if (!mintAddress) {
|
|
160
|
+
return { valid: false, error: `RVUI not deployed on ${config.network}` };
|
|
161
|
+
}
|
|
162
|
+
const tx = await rpc
|
|
163
|
+
.getTransaction(signature(txSignature), {
|
|
164
|
+
commitment: config.paymentCommitment,
|
|
165
|
+
encoding: 'jsonParsed',
|
|
166
|
+
maxSupportedTransactionVersion: 0,
|
|
167
|
+
})
|
|
168
|
+
.send();
|
|
169
|
+
if (!tx) {
|
|
170
|
+
return { valid: false, error: 'Transaction not found or not yet finalized' };
|
|
171
|
+
}
|
|
172
|
+
if (tx.meta?.err) {
|
|
173
|
+
return { valid: false, error: `Transaction failed: ${JSON.stringify(tx.meta.err)}` };
|
|
174
|
+
}
|
|
175
|
+
// Parse token balance changes from transaction meta
|
|
176
|
+
const preBalances = tx.meta?.preTokenBalances ?? [];
|
|
177
|
+
const postBalances = tx.meta?.postTokenBalances ?? [];
|
|
178
|
+
// In @solana/kit, addresses are strings — no PublicKey class needed
|
|
179
|
+
const recipientPost = postBalances.find((b) => b.mint === mintAddress &&
|
|
180
|
+
b.owner === expectedRecipient &&
|
|
181
|
+
b.programId === RVUI_TOKEN_PROGRAM);
|
|
182
|
+
const recipientPre = preBalances.find((b) => b.mint === mintAddress &&
|
|
183
|
+
b.owner === expectedRecipient &&
|
|
184
|
+
b.programId === RVUI_TOKEN_PROGRAM);
|
|
185
|
+
if (!recipientPost) {
|
|
186
|
+
return { valid: false, error: 'Recipient did not receive RVUI tokens in this transaction' };
|
|
187
|
+
}
|
|
188
|
+
const preAmount = BigInt(recipientPre?.uiTokenAmount.amount ?? '0');
|
|
189
|
+
const postAmount = BigInt(recipientPost.uiTokenAmount.amount);
|
|
190
|
+
const received = postAmount - preAmount;
|
|
191
|
+
if (received < expectedAmountRaw) {
|
|
192
|
+
return {
|
|
193
|
+
valid: false,
|
|
194
|
+
error: `Insufficient payment: expected ${expectedAmountRaw}, received ${received}`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return { valid: true };
|
|
198
|
+
}, 'verifyRvuiPayment');
|
|
199
|
+
}
|
|
200
|
+
// =============================================================================
|
|
201
|
+
// Test-only exports
|
|
202
|
+
// =============================================================================
|
|
203
|
+
export const __solanaCircuitBreaker = solanaCircuitBreaker;
|
|
204
|
+
export const __CIRCUIT_BREAKER_CONFIG = CIRCUIT_BREAKER_CONFIG;
|
|
205
|
+
export const __RETRY_CONFIG = RETRY_CONFIG;
|
|
206
|
+
export const __resetCircuitBreaker = () => solanaCircuitBreaker.reset();
|
|
207
|
+
export const __resetConnection = () => {
|
|
208
|
+
_rpc = null;
|
|
209
|
+
_rpcUrl = null;
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/revealcoin/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RevealCoin RPC Configuration
|
|
3
|
+
*
|
|
4
|
+
* Parameterized configuration for Solana RPC connections and payment
|
|
5
|
+
* verification. All thresholds are overridable for testing.
|
|
6
|
+
*/
|
|
7
|
+
import type { SolanaNetwork } from '@revealui/contracts';
|
|
8
|
+
export interface RevealCoinConfig {
|
|
9
|
+
/** Solana network to connect to. Default: 'devnet' */
|
|
10
|
+
network: SolanaNetwork;
|
|
11
|
+
/** Solana RPC URL override. If empty, uses default cluster URL for the network. */
|
|
12
|
+
rpcUrl: string;
|
|
13
|
+
/** Commitment level for balance queries. Default: 'confirmed' */
|
|
14
|
+
queryCommitment: 'processed' | 'confirmed' | 'finalized';
|
|
15
|
+
/** Commitment level for payment verification. Default: 'finalized' */
|
|
16
|
+
paymentCommitment: 'confirmed' | 'finalized';
|
|
17
|
+
/** Whether RVUI payments are enabled. Default: false */
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/** Wallet address to receive RVUI payments. Required when enabled. */
|
|
20
|
+
receivingWallet: string;
|
|
21
|
+
/** Balance poll interval in milliseconds. Default: 60_000 */
|
|
22
|
+
pollIntervalMs: number;
|
|
23
|
+
}
|
|
24
|
+
/** Read RevealCoin configuration from environment variables. */
|
|
25
|
+
export declare function getRevealCoinConfig(): RevealCoinConfig;
|
|
26
|
+
/** Override configuration (for testing or runtime reconfiguration). */
|
|
27
|
+
export declare function configureRevealCoin(overrides: Partial<RevealCoinConfig>): void;
|
|
28
|
+
/** Reset configuration to defaults. */
|
|
29
|
+
export declare function resetRevealCoinConfig(): void;
|
|
30
|
+
/** Resolve the RPC URL for the current network configuration. */
|
|
31
|
+
export declare function resolveRpcUrl(cfg?: RevealCoinConfig): string;
|
|
32
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/revealcoin/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,OAAO,EAAE,aAAa,CAAC;IACvB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,eAAe,EAAE,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;IACzD,sEAAsE;IACtE,iBAAiB,EAAE,WAAW,GAAG,WAAW,CAAC;IAC7C,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;CACxB;AAkBD,gEAAgE;AAChE,wBAAgB,mBAAmB,IAAI,gBAAgB,CAUtD;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAE9E;AAED,uCAAuC;AACvC,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAYD,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAI5D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RevealCoin RPC Configuration
|
|
3
|
+
*
|
|
4
|
+
* Parameterized configuration for Solana RPC connections and payment
|
|
5
|
+
* verification. All thresholds are overridable for testing.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_CONFIG = {
|
|
8
|
+
network: 'devnet',
|
|
9
|
+
rpcUrl: '',
|
|
10
|
+
queryCommitment: 'confirmed',
|
|
11
|
+
paymentCommitment: 'finalized',
|
|
12
|
+
enabled: false,
|
|
13
|
+
receivingWallet: '',
|
|
14
|
+
pollIntervalMs: 60_000,
|
|
15
|
+
};
|
|
16
|
+
let config = { ...DEFAULT_CONFIG };
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Public API
|
|
19
|
+
// =============================================================================
|
|
20
|
+
/** Read RevealCoin configuration from environment variables. */
|
|
21
|
+
export function getRevealCoinConfig() {
|
|
22
|
+
const network = process.env.SOLANA_NETWORK ?? DEFAULT_CONFIG.network;
|
|
23
|
+
return {
|
|
24
|
+
...config,
|
|
25
|
+
network,
|
|
26
|
+
rpcUrl: process.env.SOLANA_RPC_URL ?? config.rpcUrl,
|
|
27
|
+
enabled: process.env.RVUI_PAYMENTS_ENABLED === 'true',
|
|
28
|
+
receivingWallet: process.env.RVUI_RECEIVING_WALLET ?? config.receivingWallet,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Override configuration (for testing or runtime reconfiguration). */
|
|
32
|
+
export function configureRevealCoin(overrides) {
|
|
33
|
+
config = { ...DEFAULT_CONFIG, ...overrides };
|
|
34
|
+
}
|
|
35
|
+
/** Reset configuration to defaults. */
|
|
36
|
+
export function resetRevealCoinConfig() {
|
|
37
|
+
config = { ...DEFAULT_CONFIG };
|
|
38
|
+
}
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// RPC URL Resolution
|
|
41
|
+
// =============================================================================
|
|
42
|
+
const CLUSTER_URLS = {
|
|
43
|
+
devnet: 'https://api.devnet.solana.com',
|
|
44
|
+
testnet: 'https://api.testnet.solana.com',
|
|
45
|
+
'mainnet-beta': 'https://api.mainnet-beta.solana.com',
|
|
46
|
+
};
|
|
47
|
+
/** Resolve the RPC URL for the current network configuration. */
|
|
48
|
+
export function resolveRpcUrl(cfg) {
|
|
49
|
+
const c = cfg ?? getRevealCoinConfig();
|
|
50
|
+
if (c.rpcUrl)
|
|
51
|
+
return c.rpcUrl;
|
|
52
|
+
return CLUSTER_URLS[c.network] ?? 'https://api.devnet.solana.com';
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/revealcoin/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,MAAM,cAAc,GAAqB;IACvC,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,EAAE;IACV,eAAe,EAAE,WAAW;IAC5B,iBAAiB,EAAE,WAAW;IAC9B,OAAO,EAAE,KAAK;IACd,eAAe,EAAE,EAAE;IACnB,cAAc,EAAE,MAAM;CACvB,CAAC;AAEF,IAAI,MAAM,GAAqB,EAAE,GAAG,cAAc,EAAE,CAAC;AAErD,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF,gEAAgE;AAChE,MAAM,UAAU,mBAAmB;IACjC,MAAM,OAAO,GAAI,OAAO,CAAC,GAAG,CAAC,cAAgC,IAAI,cAAc,CAAC,OAAO,CAAC;IAExF,OAAO;QACL,GAAG,MAAM;QACT,OAAO;QACP,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM;QACnD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,MAAM;QACrD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,MAAM,CAAC,eAAe;KAC7E,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,mBAAmB,CAAC,SAAoC;IACtE,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,SAAS,EAAE,CAAC;AAC/C,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,qBAAqB;IACnC,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;AACjC,CAAC;AAED,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,MAAM,YAAY,GAAkC;IAClD,MAAM,EAAE,+BAA+B;IACvC,OAAO,EAAE,gCAAgC;IACzC,cAAc,EAAE,qCAAqC;CACtD,CAAC;AAEF,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,GAAsB;IAClD,MAAM,CAAC,GAAG,GAAG,IAAI,mBAAmB,EAAE,CAAC;IACvC,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC;IAC9B,OAAO,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,+BAA+B,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { configureRevealCoin, getRevealCoinConfig, resetRevealCoinConfig, resolveRpcUrl, type RevealCoinConfig, } from './config.js';
|
|
2
|
+
export { getRvuiBalance, type RvuiBalance, verifyRvuiPayment, } from './client.js';
|
|
3
|
+
export { configureSafeguards, getSafeguardsConfig, getTwapPrice, isDuplicateTransaction, isDiscountCapExceeded, isPaymentOverMaximum, isPriceCircuitBreakerOpen, isWalletRateLimited, recordPayment, recordPriceSnapshot, resetSafeguardsConfig, type RevealCoinSafeguardsConfig, type SafeguardCheckResult, validatePayment, } from './safeguards.js';
|
|
4
|
+
export { configurePriceOracle, fetchRvuiPrice, getPriceOracleConfig, isPriceOracleRunning, type PriceOracleConfig, recordPriceFromJupiter, rvuiToUsd, startPriceOracle, stopPriceOracle, usdToRvui, } from './oracle.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/revealcoin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EACzB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,sBAAsB,EACtB,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,SAAS,GACV,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { configureRevealCoin, getRevealCoinConfig, resetRevealCoinConfig, resolveRpcUrl, } from './config.js';
|
|
2
|
+
export { getRvuiBalance, verifyRvuiPayment, } from './client.js';
|
|
3
|
+
export { configureSafeguards, getSafeguardsConfig, getTwapPrice, isDuplicateTransaction, isDiscountCapExceeded, isPaymentOverMaximum, isPriceCircuitBreakerOpen, isWalletRateLimited, recordPayment, recordPriceSnapshot, resetSafeguardsConfig, validatePayment, } from './safeguards.js';
|
|
4
|
+
export { configurePriceOracle, fetchRvuiPrice, getPriceOracleConfig, isPriceOracleRunning, recordPriceFromJupiter, rvuiToUsd, startPriceOracle, stopPriceOracle, usdToRvui, } from './oracle.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/revealcoin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,GAEd,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,cAAc,EAEd,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EAGrB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EAEpB,sBAAsB,EACtB,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,SAAS,GACV,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jupiter Price Oracle for RVUI → USD conversion.
|
|
3
|
+
*
|
|
4
|
+
* Fetches live RVUI price from Jupiter Price API v3, records snapshots
|
|
5
|
+
* to the database for TWAP calculation, and provides a polling loop
|
|
6
|
+
* for continuous price monitoring.
|
|
7
|
+
*
|
|
8
|
+
* Per whitepaper Section 9.4:
|
|
9
|
+
* - Source: Jupiter aggregator price feed (RVUI/USDC pair)
|
|
10
|
+
* - Window: 1-hour TWAP to smooth volatility
|
|
11
|
+
* - Update frequency: Every 60 seconds
|
|
12
|
+
* - Fallback: If oracle is unavailable, fiat pricing applies (no RVUI discount)
|
|
13
|
+
*
|
|
14
|
+
* Requires JUPITER_API_KEY env var (free tier: 1 RPS, sufficient for 60s polling).
|
|
15
|
+
*/
|
|
16
|
+
export interface PriceOracleConfig {
|
|
17
|
+
/** Jupiter Price API v3 endpoint. */
|
|
18
|
+
apiUrl: string;
|
|
19
|
+
/** Jupiter API key (required). Free tier at portal.jup.ag */
|
|
20
|
+
apiKey: string;
|
|
21
|
+
/** Polling interval in milliseconds. Default: 60_000 (60 seconds) */
|
|
22
|
+
pollIntervalMs: number;
|
|
23
|
+
/** Request timeout in milliseconds. Default: 10_000 */
|
|
24
|
+
requestTimeoutMs: number;
|
|
25
|
+
/** Maximum consecutive failures before stopping. Default: 10 */
|
|
26
|
+
maxConsecutiveFailures: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function configurePriceOracle(overrides: Partial<PriceOracleConfig>): void;
|
|
29
|
+
export declare function getPriceOracleConfig(): PriceOracleConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Fetch the current RVUI price in USD from Jupiter Price API v3.
|
|
32
|
+
*
|
|
33
|
+
* Returns null if:
|
|
34
|
+
* - No API key configured
|
|
35
|
+
* - RVUI mint not found on the active network
|
|
36
|
+
* - Jupiter returns no price data (no recent trades)
|
|
37
|
+
* - Network/API error
|
|
38
|
+
*/
|
|
39
|
+
export declare function fetchRvuiPrice(): Promise<{
|
|
40
|
+
priceUsd: number;
|
|
41
|
+
liquidity: number;
|
|
42
|
+
blockId: number | null;
|
|
43
|
+
priceChange24h: number | null;
|
|
44
|
+
} | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Fetch the current price and record a snapshot for TWAP calculation.
|
|
47
|
+
*
|
|
48
|
+
* Returns the recorded price or null if fetch failed.
|
|
49
|
+
*/
|
|
50
|
+
export declare function recordPriceFromJupiter(): Promise<number | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Convert an RVUI amount to its USD equivalent using TWAP.
|
|
53
|
+
*
|
|
54
|
+
* Returns null if no TWAP price is available (oracle offline or
|
|
55
|
+
* insufficient snapshots). Callers should fall back to fiat-only pricing.
|
|
56
|
+
*/
|
|
57
|
+
export declare function rvuiToUsd(rvuiAmount: number): Promise<number | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Convert a USD amount to the equivalent RVUI using TWAP.
|
|
60
|
+
*
|
|
61
|
+
* Returns null if no TWAP price is available.
|
|
62
|
+
*/
|
|
63
|
+
export declare function usdToRvui(usdAmount: number): Promise<number | null>;
|
|
64
|
+
/**
|
|
65
|
+
* Start the price oracle polling loop.
|
|
66
|
+
*
|
|
67
|
+
* Fetches and records RVUI price at the configured interval.
|
|
68
|
+
* Stops automatically after maxConsecutiveFailures.
|
|
69
|
+
*
|
|
70
|
+
* Call stopPriceOracle() to stop manually.
|
|
71
|
+
*/
|
|
72
|
+
export declare function startPriceOracle(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Stop the price oracle polling loop.
|
|
75
|
+
*/
|
|
76
|
+
export declare function stopPriceOracle(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Check if the price oracle is currently running.
|
|
79
|
+
*/
|
|
80
|
+
export declare function isPriceOracleRunning(): boolean;
|
|
81
|
+
//# sourceMappingURL=oracle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oracle.d.ts","sourceRoot":"","sources":["../../src/revealcoin/oracle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAcH,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAYD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAEhF;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,CAKxD;AAqBD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,IAAI,CAAC,CAyDR;AAMD;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAarE;AAMD;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAI1E;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIzE;AASD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CA0BvC;AAkBD;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jupiter Price Oracle for RVUI → USD conversion.
|
|
3
|
+
*
|
|
4
|
+
* Fetches live RVUI price from Jupiter Price API v3, records snapshots
|
|
5
|
+
* to the database for TWAP calculation, and provides a polling loop
|
|
6
|
+
* for continuous price monitoring.
|
|
7
|
+
*
|
|
8
|
+
* Per whitepaper Section 9.4:
|
|
9
|
+
* - Source: Jupiter aggregator price feed (RVUI/USDC pair)
|
|
10
|
+
* - Window: 1-hour TWAP to smooth volatility
|
|
11
|
+
* - Update frequency: Every 60 seconds
|
|
12
|
+
* - Fallback: If oracle is unavailable, fiat pricing applies (no RVUI discount)
|
|
13
|
+
*
|
|
14
|
+
* Requires JUPITER_API_KEY env var (free tier: 1 RPS, sufficient for 60s polling).
|
|
15
|
+
*/
|
|
16
|
+
import { RVUI_MINT_ADDRESSES } from '@revealui/contracts';
|
|
17
|
+
import { createLogger } from '@revealui/core/observability/logger';
|
|
18
|
+
import { getRevealCoinConfig } from './config.js';
|
|
19
|
+
import { getTwapPrice, recordPriceSnapshot } from './safeguards.js';
|
|
20
|
+
const logger = createLogger({ service: 'RevealCoin:Oracle' });
|
|
21
|
+
const DEFAULT_CONFIG = {
|
|
22
|
+
apiUrl: 'https://api.jup.ag/price/v3',
|
|
23
|
+
apiKey: '',
|
|
24
|
+
pollIntervalMs: 60_000,
|
|
25
|
+
requestTimeoutMs: 10_000,
|
|
26
|
+
maxConsecutiveFailures: 10,
|
|
27
|
+
};
|
|
28
|
+
let oracleConfig = { ...DEFAULT_CONFIG };
|
|
29
|
+
export function configurePriceOracle(overrides) {
|
|
30
|
+
oracleConfig = { ...DEFAULT_CONFIG, ...overrides };
|
|
31
|
+
}
|
|
32
|
+
export function getPriceOracleConfig() {
|
|
33
|
+
return {
|
|
34
|
+
...oracleConfig,
|
|
35
|
+
apiKey: process.env.JUPITER_API_KEY ?? oracleConfig.apiKey,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// Price Fetching
|
|
40
|
+
// =============================================================================
|
|
41
|
+
/**
|
|
42
|
+
* Fetch the current RVUI price in USD from Jupiter Price API v3.
|
|
43
|
+
*
|
|
44
|
+
* Returns null if:
|
|
45
|
+
* - No API key configured
|
|
46
|
+
* - RVUI mint not found on the active network
|
|
47
|
+
* - Jupiter returns no price data (no recent trades)
|
|
48
|
+
* - Network/API error
|
|
49
|
+
*/
|
|
50
|
+
export async function fetchRvuiPrice() {
|
|
51
|
+
const config = getPriceOracleConfig();
|
|
52
|
+
if (!config.apiKey) {
|
|
53
|
+
logger.debug('Jupiter API key not configured, skipping price fetch');
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const rvuiConfig = getRevealCoinConfig();
|
|
57
|
+
const mintAddress = RVUI_MINT_ADDRESSES[rvuiConfig.network];
|
|
58
|
+
if (!mintAddress) {
|
|
59
|
+
logger.warn('No RVUI mint address for network', { network: rvuiConfig.network });
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const url = `${config.apiUrl}?ids=${mintAddress}`;
|
|
64
|
+
const response = await fetch(url, {
|
|
65
|
+
headers: { 'x-api-key': config.apiKey },
|
|
66
|
+
signal: AbortSignal.timeout(config.requestTimeoutMs),
|
|
67
|
+
});
|
|
68
|
+
if (response.status === 429) {
|
|
69
|
+
logger.warn('Jupiter API rate limited');
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (response.status === 401) {
|
|
73
|
+
logger.error('Jupiter API key invalid or expired');
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
logger.warn('Jupiter API error', { status: response.status });
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const data = (await response.json());
|
|
81
|
+
const entry = data[mintAddress];
|
|
82
|
+
if (!entry) {
|
|
83
|
+
// Token has no recent trades — no price available
|
|
84
|
+
logger.debug('No Jupiter price data for RVUI', { mint: mintAddress });
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
priceUsd: entry.usdPrice,
|
|
89
|
+
liquidity: entry.liquidity,
|
|
90
|
+
blockId: entry.blockId,
|
|
91
|
+
priceChange24h: entry.priceChange24h,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
96
|
+
logger.warn('Failed to fetch RVUI price from Jupiter', { error: message });
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// =============================================================================
|
|
101
|
+
// Snapshot Recording
|
|
102
|
+
// =============================================================================
|
|
103
|
+
/**
|
|
104
|
+
* Fetch the current price and record a snapshot for TWAP calculation.
|
|
105
|
+
*
|
|
106
|
+
* Returns the recorded price or null if fetch failed.
|
|
107
|
+
*/
|
|
108
|
+
export async function recordPriceFromJupiter() {
|
|
109
|
+
const priceData = await fetchRvuiPrice();
|
|
110
|
+
if (!priceData)
|
|
111
|
+
return null;
|
|
112
|
+
await recordPriceSnapshot(priceData.priceUsd, 'jupiter-v3');
|
|
113
|
+
logger.debug('Recorded RVUI price snapshot', {
|
|
114
|
+
priceUsd: priceData.priceUsd,
|
|
115
|
+
liquidity: priceData.liquidity,
|
|
116
|
+
blockId: priceData.blockId,
|
|
117
|
+
});
|
|
118
|
+
return priceData.priceUsd;
|
|
119
|
+
}
|
|
120
|
+
// =============================================================================
|
|
121
|
+
// RVUI → USD Conversion
|
|
122
|
+
// =============================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Convert an RVUI amount to its USD equivalent using TWAP.
|
|
125
|
+
*
|
|
126
|
+
* Returns null if no TWAP price is available (oracle offline or
|
|
127
|
+
* insufficient snapshots). Callers should fall back to fiat-only pricing.
|
|
128
|
+
*/
|
|
129
|
+
export async function rvuiToUsd(rvuiAmount) {
|
|
130
|
+
const twap = await getTwapPrice();
|
|
131
|
+
if (twap === null)
|
|
132
|
+
return null;
|
|
133
|
+
return rvuiAmount * twap;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Convert a USD amount to the equivalent RVUI using TWAP.
|
|
137
|
+
*
|
|
138
|
+
* Returns null if no TWAP price is available.
|
|
139
|
+
*/
|
|
140
|
+
export async function usdToRvui(usdAmount) {
|
|
141
|
+
const twap = await getTwapPrice();
|
|
142
|
+
if (twap === null || twap === 0)
|
|
143
|
+
return null;
|
|
144
|
+
return usdAmount / twap;
|
|
145
|
+
}
|
|
146
|
+
// =============================================================================
|
|
147
|
+
// Polling Loop
|
|
148
|
+
// =============================================================================
|
|
149
|
+
let pollTimer = null;
|
|
150
|
+
let consecutiveFailures = 0;
|
|
151
|
+
/**
|
|
152
|
+
* Start the price oracle polling loop.
|
|
153
|
+
*
|
|
154
|
+
* Fetches and records RVUI price at the configured interval.
|
|
155
|
+
* Stops automatically after maxConsecutiveFailures.
|
|
156
|
+
*
|
|
157
|
+
* Call stopPriceOracle() to stop manually.
|
|
158
|
+
*/
|
|
159
|
+
export function startPriceOracle() {
|
|
160
|
+
if (pollTimer) {
|
|
161
|
+
logger.warn('Price oracle already running');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const config = getPriceOracleConfig();
|
|
165
|
+
if (!config.apiKey) {
|
|
166
|
+
logger.info('Jupiter API key not configured — price oracle disabled');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
consecutiveFailures = 0;
|
|
170
|
+
logger.info('Starting RVUI price oracle', {
|
|
171
|
+
intervalMs: config.pollIntervalMs,
|
|
172
|
+
apiUrl: config.apiUrl,
|
|
173
|
+
});
|
|
174
|
+
// Initial fetch
|
|
175
|
+
void tick(config);
|
|
176
|
+
pollTimer = setInterval(() => {
|
|
177
|
+
void tick(config);
|
|
178
|
+
}, config.pollIntervalMs);
|
|
179
|
+
}
|
|
180
|
+
async function tick(config) {
|
|
181
|
+
const price = await recordPriceFromJupiter();
|
|
182
|
+
if (price === null) {
|
|
183
|
+
consecutiveFailures++;
|
|
184
|
+
if (consecutiveFailures >= config.maxConsecutiveFailures) {
|
|
185
|
+
logger.error('Price oracle stopped — too many consecutive failures', undefined, {
|
|
186
|
+
failures: consecutiveFailures,
|
|
187
|
+
});
|
|
188
|
+
stopPriceOracle();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
consecutiveFailures = 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Stop the price oracle polling loop.
|
|
197
|
+
*/
|
|
198
|
+
export function stopPriceOracle() {
|
|
199
|
+
if (pollTimer) {
|
|
200
|
+
clearInterval(pollTimer);
|
|
201
|
+
pollTimer = null;
|
|
202
|
+
logger.info('Price oracle stopped');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if the price oracle is currently running.
|
|
207
|
+
*/
|
|
208
|
+
export function isPriceOracleRunning() {
|
|
209
|
+
return pollTimer !== null;
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=oracle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oracle.js","sourceRoot":"","sources":["../../src/revealcoin/oracle.ts"],"names":[],"mappings":"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"}
|