@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.
527 lines (526 loc) • 21.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NitroliteService = void 0;
const viem_1 = require("viem");
const generated_1 = require("../../abis/generated");
const errors_1 = require("../../errors");
const executeWriteContract = async (walletClient, request, account) => {
return walletClient.writeContract({
...request,
account,
});
};
class NitroliteService {
constructor(publicClient, addresses, walletClient, account) {
if (!publicClient) {
throw new errors_1.Errors.MissingParameterError('publicClient');
}
if (!addresses || !addresses.custody) {
throw new errors_1.Errors.MissingParameterError('addresses.custody');
}
this.publicClient = publicClient;
this.walletClient = walletClient;
this.account = account || walletClient?.account;
this.addresses = addresses;
}
ensureWalletClient() {
if (!this.walletClient) {
throw new errors_1.Errors.WalletClientRequiredError();
}
return this.walletClient;
}
ensureAccount() {
if (!this.account) {
throw new errors_1.Errors.AccountRequiredError();
}
return this.account;
}
get custodyAddress() {
return this.addresses.custody;
}
convertChannelForABI(channel) {
return {
participants: (channel.participants || []),
adjudicator: channel.adjudicator,
challenge: channel.challenge,
nonce: channel.nonce,
};
}
convertStateForABI(state) {
return {
intent: state.intent,
version: state.version,
data: state.data,
allocations: (state.allocations || []).map((alloc) => ({
destination: alloc.destination,
token: alloc.token,
amount: alloc.amount,
})),
sigs: (state.sigs || []).map((sig) => ({
v: sig.v,
r: sig.r,
s: sig.s,
})),
};
}
convertSignatureForABI(signature) {
return {
v: signature.v,
r: signature.r,
s: signature.s,
};
}
convertChannelFromContract(contractChannel) {
return {
participants: [...contractChannel.participants],
adjudicator: contractChannel.adjudicator,
challenge: contractChannel.challenge,
nonce: contractChannel.nonce,
};
}
convertStateFromContract(contractState) {
return {
intent: contractState.intent,
version: contractState.version,
data: contractState.data,
allocations: contractState.allocations.map((alloc) => ({
destination: alloc.destination,
token: alloc.token,
amount: alloc.amount,
})),
sigs: contractState.sigs.map((sig) => ({
v: sig.v,
r: sig.r,
s: sig.s,
})),
};
}
async prepareDeposit(tokenAddress, amount) {
const account = this.ensureAccount();
const operationName = 'prepareDeposit';
const accountAddress = typeof account === 'string' ? account : account.address;
try {
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'deposit',
args: [accountAddress, tokenAddress, amount],
account: account,
value: tokenAddress === viem_1.zeroAddress ? amount : 0n,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { tokenAddress, amount });
}
}
async deposit(tokenAddress, amount) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'deposit';
try {
const request = await this.prepareDeposit(tokenAddress, amount);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { tokenAddress, amount });
}
}
async prepareCreateChannel(channel, initial) {
const account = this.ensureAccount();
const operationName = 'prepareCreateChannel';
try {
const abiChannel = this.convertChannelForABI(channel);
const abiState = this.convertStateForABI(initial);
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'create',
args: [abiChannel, abiState],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { channel, initial });
}
}
async createChannel(channel, initial) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'createChannel';
try {
const request = await this.prepareCreateChannel(channel, initial);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { channel, initial });
}
}
async prepareDepositAndCreateChannel(tokenAddress, amount, channel, initial) {
const account = this.ensureAccount();
const operationName = 'prepareDepositAndCreateChannel';
const accountAddress = typeof account === 'string' ? account : account.address;
try {
const abiChannel = this.convertChannelForABI(channel);
const abiState = this.convertStateForABI(initial);
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'depositAndCreate',
args: [tokenAddress, amount, abiChannel, abiState],
account: account,
value: tokenAddress === viem_1.zeroAddress ? amount : 0n,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { tokenAddress, amount, channel, initial });
}
}
async depositAndCreateChannel(tokenAddress, amount, channel, initial) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'depositAndCreateChannel';
try {
const request = await this.prepareDepositAndCreateChannel(tokenAddress, amount, channel, initial);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { tokenAddress, amount, channel, initial });
}
}
async prepareJoinChannel(channelId, index, sig) {
const account = this.ensureAccount();
const operationName = 'prepareJoinChannel';
try {
const abiSignature = this.convertSignatureForABI(sig);
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'join',
args: [channelId, index, abiSignature],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { channelId, index });
}
}
async joinChannel(channelId, index, sig) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'joinChannel';
try {
const request = await this.prepareJoinChannel(channelId, index, sig);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { channelId, index });
}
}
async prepareCheckpoint(channelId, candidate, proofs = []) {
const account = this.ensureAccount();
const operationName = 'prepareCheckpoint';
try {
const abiCandidate = this.convertStateForABI(candidate);
const abiProofs = proofs.map((proof) => this.convertStateForABI(proof));
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'checkpoint',
args: [channelId, abiCandidate, abiProofs],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { channelId });
}
}
async checkpoint(channelId, candidate, proofs = []) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'checkpoint';
try {
const request = await this.prepareCheckpoint(channelId, candidate, proofs);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { channelId });
}
}
async prepareChallenge(channelId, candidate, proofs = [], challengerSig) {
const account = this.ensureAccount();
const operationName = 'prepareChallenge';
try {
const abiCandidate = this.convertStateForABI(candidate);
const abiProofs = proofs.map((proof) => this.convertStateForABI(proof));
const challengerSigABI = this.convertSignatureForABI(challengerSig);
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'challenge',
args: [channelId, abiCandidate, abiProofs, challengerSigABI],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { channelId });
}
}
async challenge(channelId, candidate, proofs = [], challengerSig) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'challenge';
try {
const request = await this.prepareChallenge(channelId, candidate, proofs, challengerSig);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { channelId });
}
}
async prepareResize(channelId, candidate, proofs = []) {
const account = this.ensureAccount();
const operationName = 'prepareResize';
try {
const abiCandidate = this.convertStateForABI(candidate);
const abiProofs = proofs.map((proof) => this.convertStateForABI(proof));
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'resize',
args: [channelId, abiCandidate, abiProofs],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { channelId });
}
}
async resize(channelId, candidate, proofs = []) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'resize';
try {
const request = await this.prepareResize(channelId, candidate, proofs);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { channelId });
}
}
async prepareClose(channelId, candidate, proofs = []) {
const account = this.ensureAccount();
const operationName = 'prepareClose';
try {
const abiCandidate = this.convertStateForABI(candidate);
const abiProofs = proofs.map((proof) => this.convertStateForABI(proof));
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'close',
args: [channelId, abiCandidate, abiProofs],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { channelId });
}
}
async close(channelId, candidate, proofs = []) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'close';
try {
const request = await this.prepareClose(channelId, candidate, proofs);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { channelId });
}
}
async prepareWithdraw(tokenAddress, amount) {
const account = this.ensureAccount();
const operationName = 'prepareWithdraw';
try {
const { request } = await this.publicClient.simulateContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: 'withdraw',
args: [tokenAddress, amount],
account: account,
});
return request;
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractCallError(operationName, error, { tokenAddress, amount });
}
}
async withdraw(tokenAddress, amount) {
const walletClient = this.ensureWalletClient();
const account = this.ensureAccount();
const operationName = 'withdraw';
try {
const request = await this.prepareWithdraw(tokenAddress, amount);
return await executeWriteContract(walletClient, request, account);
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.TransactionError(operationName, error, { tokenAddress, amount });
}
}
async getOpenChannels(account) {
const functionName = 'getOpenChannels';
const accountsArg = Array.isArray(account) ? account : [account];
if (accountsArg.length === 0) {
throw new errors_1.Errors.MissingParameterError('accounts');
}
try {
const result = await this.publicClient.readContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: functionName,
args: [accountsArg],
});
if (Array.isArray(account)) {
return result;
}
else {
return result[0];
}
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractReadError(functionName, error, { accountsArg });
}
}
async getAccountBalance(user, token) {
const functionName = 'getAccountsBalances';
const usersArg = Array.isArray(user) ? user : [user];
const tokensArg = Array.isArray(token) ? token : [token];
if (usersArg.length === 0 || tokensArg.length === 0) {
throw new errors_1.Errors.MissingParameterError('users or tokens');
}
try {
const result = await this.publicClient.readContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: functionName,
args: [usersArg, tokensArg],
});
if (Array.isArray(token)) {
if (Array.isArray(user)) {
return result;
}
else {
return result[0];
}
}
else {
if (Array.isArray(user)) {
return result[0];
}
else {
return result[0][0];
}
}
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractReadError(functionName, error, { usersArg, tokensArg });
}
}
async getChannelBalance(channelId, token) {
const functionName = 'getChannelBalances';
const tokensArg = Array.isArray(token) ? token : [token];
if (tokensArg.length === 0) {
throw new errors_1.Errors.MissingParameterError('tokens');
}
try {
const result = await this.publicClient.readContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: functionName,
args: [channelId, tokensArg],
});
if (Array.isArray(token)) {
return result;
}
else {
return result[0];
}
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractReadError(functionName, error, { channelId, tokensArg });
}
}
async getChannelData(channelId) {
const functionName = 'getChannelData';
try {
const result = await this.publicClient.readContract({
address: this.custodyAddress,
abi: generated_1.custodyAbi,
functionName: functionName,
args: [channelId],
});
return {
channel: this.convertChannelFromContract(result[0]),
status: result[1],
wallets: result[2],
challengeExpiry: result[3],
lastValidState: this.convertStateFromContract(result[4]),
};
}
catch (error) {
if (error instanceof errors_1.Errors.NitroliteError)
throw error;
throw new errors_1.Errors.ContractReadError(functionName, error, { channelId });
}
}
}
exports.NitroliteService = NitroliteService;