UNPKG

@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
"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;