@erc7824/nitrolite
Version:
The Nitrolite SDK empowers developers to build high-performance, scalable web3 applications using state channels. It's designed to provide near-instant transactions and significantly improved user experiences by minimizing direct blockchain interactions.
143 lines (142 loc) • 5.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NitroliteRPC = void 0;
const types_1 = require("./types");
const utils_1 = require("./utils");
class NitroliteRPC {
static createRequest(requestId = (0, utils_1.generateRequestId)(), method, params = [], timestamp = (0, utils_1.getCurrentTimestamp)()) {
const requestData = [requestId, method, params, timestamp];
const message = { req: requestData };
return message;
}
static createAppRequest(requestId = (0, utils_1.generateRequestId)(), method, params = [], timestamp = (0, utils_1.getCurrentTimestamp)(), sid) {
const requestData = [requestId, method, params, timestamp];
const message = { req: requestData, sid };
return message;
}
static parseResponse(rawMessage) {
let message;
try {
message = typeof rawMessage === 'string' ? JSON.parse(rawMessage) : rawMessage;
}
catch (e) {
console.error('Failed to parse incoming message:', e);
return {
isValid: false,
error: 'Message parsing failed',
};
}
if (!message ||
typeof message !== 'object' ||
!message.res ||
!Array.isArray(message.res) ||
message.res.length !== 4) {
return {
isValid: false,
error: "Invalid message structure: Missing or invalid 'res' array.",
};
}
const [requestId, method, dataPayload, timestamp] = message.res;
const sid = typeof message.sid === 'string' ? message.sid : undefined;
if (typeof requestId !== 'number' ||
typeof method !== 'string' ||
!Object.values(types_1.RPCMethod).includes(method) ||
!Array.isArray(dataPayload) ||
typeof timestamp !== 'number') {
return {
isValid: false,
requestId,
method,
sid,
timestamp,
error: "Invalid 'res' payload structure or types.",
};
}
let data;
let isError = false;
if (method === types_1.RPCMethod.Error) {
isError = true;
if (dataPayload.length === 1 &&
typeof dataPayload[0] === 'object' &&
dataPayload[0] !== null &&
'error' in dataPayload[0]) {
data = dataPayload[0];
}
else {
return {
isValid: false,
requestId,
method,
sid,
timestamp,
error: 'Malformed error response payload.',
};
}
}
else {
data = dataPayload;
}
return {
isValid: true,
isError,
requestId,
method: method,
data,
sid,
timestamp,
};
}
static isResponseType(response, method) {
return response.isValid && !response.isError && response.method === method;
}
static getMessagePayload(message) {
if (message.req)
return message.req;
if (message.res)
return message.res;
throw new Error("Message must contain either 'req' or 'res' field");
}
static async signRequestMessage(message, signer) {
if (!message.req) {
throw new Error("signRequestMessage can only sign request messages containing 'req'.");
}
const payload = this.getMessagePayload(message);
const signature = await signer(payload);
message.sig = [signature];
return message;
}
static async verifySingleSignature(message, expectedSigner, verifier) {
if (!message.sig || !Array.isArray(message.sig) || message.sig.length === 0) {
return false;
}
const signature = message.sig[0];
if (message.sig.length > 1) {
console.error('verifySingleSignature called on message with multiple signatures. Verifying only the first one.');
}
try {
const payload = this.getMessagePayload(message);
if (typeof signature !== 'string' || signature === '') {
return false;
}
return await verifier(payload, signature, expectedSigner);
}
catch (error) {
console.error('Error during single signature verification:', error);
return false;
}
}
static async verifyMultipleSignatures(message, expectedSigners, verifier) {
if (!message.sig || !Array.isArray(message.sig)) {
return false;
}
try {
const payload = this.getMessagePayload(message);
return await verifier(payload, message.sig, expectedSigners);
}
catch (error) {
console.error('Error during multiple signature verification:', error);
return false;
}
}
}
exports.NitroliteRPC = NitroliteRPC;