-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathplan-operations.js
More file actions
206 lines (186 loc) · 7.46 KB
/
Copy pathplan-operations.js
File metadata and controls
206 lines (186 loc) · 7.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/**
* Plan, Provider & Lease Operations for Sentinel dVPN
*
* Contains all encoder functions for plan management, provider registration,
* and node leasing. These are the 10 message types NOT in v3protocol.js.
*
* v3protocol.js handles: direct session, subscription, sub-session (3 types)
* This file handles: provider (3), plan (4), lease (2), plan-session (1) = 10 types
*/
// ─── Protobuf Encoding Primitives ────────────────────────────────────────────
// Shared with v3protocol.js — single source of truth for protobuf encoding.
import { encodeVarint, protoString, protoInt64, protoEmbedded, decToScaledInt, encodePrice } from './v3protocol.js';
// protoUint64 is identical to protoInt64 — both use varint wire type 0
function protoUint64(fieldNum, n) {
return protoInt64(fieldNum, n);
}
function protoBool(fieldNum, val) {
if (!val) return Buffer.alloc(0); // false = omit (protobuf default)
return Buffer.concat([encodeVarint((BigInt(fieldNum) << 3n) | 0n), encodeVarint(1)]);
}
// decToScaledInt and encodePrice imported from v3protocol.js (single source of truth)
/**
* Encode google.protobuf.Duration { seconds, nanos }
* Used by MsgCreatePlanRequest for plan duration.
*/
function encodeDuration({ seconds, nanos = 0 }) {
return Buffer.concat([
protoInt64(1, seconds),
nanos ? protoInt64(2, nanos) : Buffer.alloc(0),
]);
}
// ─── Provider Messages ───────────────────────────────────────────────────────
/**
* MsgRegisterProviderRequest (sentinel.provider.v3)
* Register a new provider. One wallet = one provider.
* from: sent prefix (account address)
*/
export function encodeMsgRegisterProvider({ from, name, identity, website, description }) {
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoString(2, name),
protoString(3, identity || ''),
protoString(4, website || ''),
protoString(5, description || ''),
]));
}
/**
* MsgUpdateProviderDetailsRequest (sentinel.provider.v3)
* Update existing provider info.
* from: sentprov prefix (provider address)
*/
export function encodeMsgUpdateProviderDetails({ from, name, identity, website, description }) {
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoString(2, name || ''),
protoString(3, identity || ''),
protoString(4, website || ''),
protoString(5, description || ''),
]));
}
/**
* MsgUpdateProviderStatusRequest (sentinel.provider.v3)
* Activate/deactivate provider. Status: 1=active, 2=inactive_pending, 3=inactive
* from: sentprov prefix (provider address — use sentToSentprov() to derive)
*/
export function encodeMsgUpdateProviderStatus({ from, status }) {
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoInt64(2, status),
]));
}
// ─── Plan Messages ───────────────────────────────────────────────────────────
/**
* MsgCreatePlanRequest (sentinel.plan.v3)
* Create a new subscription plan.
* from: sentprov prefix (provider address)
* bytes: total bandwidth as string (e.g. "10000000000" for 10GB)
* duration: { seconds: N } — plan validity period
* prices: [{ denom, base_value, quote_value }] — subscription cost
* isPrivate: boolean
*
* NOTE: Plans start INACTIVE by default — must send MsgUpdatePlanStatusRequest separately!
*/
export function encodeMsgCreatePlan({ from, bytes, duration, prices, isPrivate }) {
const parts = [protoString(1, from)];
if (bytes) parts.push(protoString(2, String(bytes)));
if (duration) parts.push(protoEmbedded(3, encodeDuration(
typeof duration === 'number' ? { seconds: duration } : duration
)));
for (const p of (prices || [])) {
parts.push(protoEmbedded(4, encodePrice(p)));
}
if (isPrivate) parts.push(protoBool(5, true));
return Uint8Array.from(Buffer.concat(parts));
}
/**
* MsgUpdatePlanStatusRequest (sentinel.plan.v3)
* Activate/deactivate a plan. Status: 1=active, 2=inactive_pending, 3=inactive
* from: sentprov prefix (provider address)
*/
export function encodeMsgUpdatePlanStatus({ from, id, status }) {
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoUint64(2, id),
protoInt64(3, status),
]));
}
/**
* MsgLinkNodeRequest (sentinel.plan.v3)
* Link a leased node to a plan. Requires active lease for the node.
* from: sentprov prefix (provider address)
*/
export function encodeMsgLinkNode({ from, id, nodeAddress, node_address }) {
const addr = nodeAddress || node_address;
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoUint64(2, id),
protoString(3, addr),
]));
}
/**
* MsgUnlinkNodeRequest (sentinel.plan.v3)
* Remove a node from a plan.
* from: sentprov prefix (provider address)
*/
export function encodeMsgUnlinkNode({ from, id, nodeAddress, node_address }) {
const addr = nodeAddress || node_address;
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoUint64(2, id),
protoString(3, addr),
]));
}
/**
* MsgStartSessionRequest (sentinel.plan.v3) — COMBINED subscribe + session
* Subscribes to a plan AND starts a session in one TX.
* from: sent prefix (account address)
*/
export function encodeMsgPlanStartSession({ from, id, denom = 'udvpn', renewalPricePolicy, renewal_price_policy, nodeAddress, node_address }) {
const policy = renewalPricePolicy || renewal_price_policy || 0;
const addr = nodeAddress || node_address;
const parts = [
protoString(1, from),
protoUint64(2, id),
protoString(3, denom),
];
if (policy) parts.push(protoInt64(4, policy));
if (addr) parts.push(protoString(5, addr));
return Uint8Array.from(Buffer.concat(parts));
}
// ─── Lease Messages ──────────────────────────────────────────────────────────
/**
* MsgStartLeaseRequest (sentinel.lease.v1)
* Lease a node from its operator. Provider pays node's hourly price.
* from: sentprov prefix (provider address)
*
* CRITICAL: maxPrice must EXACTLY match the node's hourly_prices from LCD.
* Any mismatch → "invalid price" error.
*/
export function encodeMsgStartLease({ from, nodeAddress, node_address, hours, maxPrice, max_price, renewalPricePolicy, renewal_price_policy }) {
const addr = nodeAddress || node_address;
const price = maxPrice || max_price;
const policy = renewalPricePolicy || renewal_price_policy || 0;
const parts = [
protoString(1, from),
protoString(2, addr),
protoInt64(3, hours),
];
if (price) parts.push(protoEmbedded(4, encodePrice(price)));
if (policy) parts.push(protoInt64(5, policy));
return Uint8Array.from(Buffer.concat(parts));
}
/**
* MsgEndLeaseRequest (sentinel.lease.v1)
* End an active lease.
* from: sentprov prefix (provider address)
*/
export function encodeMsgEndLease({ from, id }) {
return Uint8Array.from(Buffer.concat([
protoString(1, from),
protoUint64(2, id),
]));
}
// ─── Exported Helpers ────────────────────────────────────────────────────────
export { encodePrice, encodeDuration, decToScaledInt };
export { encodeVarint, protoString, protoInt64, protoUint64, protoBool, protoEmbedded };