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.

264 lines (263 loc) 11.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.NitroliteClient = void 0; const viem_1 = require("viem"); const Errors = __importStar(require("../errors")); const prepare_1 = require("./prepare"); const services_1 = require("./services"); const state_1 = require("./state"); const CUSTODY_MIN_CHALLENGE_DURATION = 3600n; class NitroliteClient { constructor(config) { if (!config.publicClient) throw new Errors.MissingParameterError('publicClient'); if (!config.walletClient) throw new Errors.MissingParameterError('walletClient'); if (!config.walletClient.account) throw new Errors.MissingParameterError('walletClient.account'); if (!config.challengeDuration) throw new Errors.MissingParameterError('challengeDuration'); if (config.challengeDuration < CUSTODY_MIN_CHALLENGE_DURATION) throw new Errors.InvalidParameterError(`The minimum challenge duration is ${CUSTODY_MIN_CHALLENGE_DURATION} seconds`); if (!config.addresses?.custody) throw new Errors.MissingParameterError('addresses.custody'); if (!config.addresses?.adjudicator) throw new Errors.MissingParameterError('addresses.adjudicator'); if (!config.addresses?.guestAddress) throw new Errors.MissingParameterError('addresses.guestAddress'); if (!config.chainId) throw new Errors.MissingParameterError('chainId'); this.publicClient = config.publicClient; this.walletClient = config.walletClient; this.stateWalletClient = config.stateWalletClient ?? config.walletClient; this.account = config.walletClient.account; this.addresses = config.addresses; this.challengeDuration = config.challengeDuration; this.chainId = config.chainId; this.nitroliteService = new services_1.NitroliteService(this.publicClient, this.addresses, this.walletClient, this.account); this.erc20Service = new services_1.Erc20Service(this.publicClient, this.walletClient); this.sharedDeps = { nitroliteService: this.nitroliteService, erc20Service: this.erc20Service, addresses: this.addresses, account: this.account, walletClient: this.walletClient, challengeDuration: this.challengeDuration, stateWalletClient: this.stateWalletClient, chainId: this.chainId, }; this.txPreparer = new prepare_1.NitroliteTransactionPreparer(this.sharedDeps); } async deposit(tokenAddress, amount) { const owner = this.account.address; const spender = this.addresses.custody; if (tokenAddress !== viem_1.zeroAddress) { const allowance = await this.erc20Service.getTokenAllowance(tokenAddress, owner, spender); if (allowance < amount) { try { const hash = await this.erc20Service.approve(tokenAddress, spender, amount); await (0, services_1.waitForTransaction)(this.publicClient, hash); } catch (err) { const error = new Errors.TokenError('Failed to approve tokens for deposit'); throw error; } } } try { const depositHash = await this.nitroliteService.deposit(tokenAddress, amount); await (0, services_1.waitForTransaction)(this.publicClient, depositHash); return depositHash; } catch (err) { throw new Errors.ContractCallError('Failed to execute deposit on contract', err); } } async createChannel(tokenAddress, params) { try { const { channel, initialState, channelId } = await (0, state_1._prepareAndSignInitialState)(tokenAddress, this.sharedDeps, params); const txHash = await this.nitroliteService.createChannel(channel, initialState); return { channelId, initialState, txHash }; } catch (err) { throw new Errors.ContractCallError('Failed to execute createChannel on contract', err); } } async depositAndCreateChannel(tokenAddress, depositAmount, params) { try { const owner = this.account.address; const spender = this.addresses.custody; const { channel, initialState, channelId } = await (0, state_1._prepareAndSignInitialState)(tokenAddress, this.sharedDeps, params); if (tokenAddress !== viem_1.zeroAddress) { const allowance = await this.erc20Service.getTokenAllowance(tokenAddress, owner, spender); if (allowance < depositAmount) { try { const hash = await this.erc20Service.approve(tokenAddress, spender, depositAmount); await (0, services_1.waitForTransaction)(this.publicClient, hash); } catch (err) { const error = new Errors.TokenError('Failed to approve tokens for deposit'); throw error; } } } const txHash = await this.nitroliteService.depositAndCreateChannel(tokenAddress, depositAmount, channel, initialState); return { channelId, initialState, txHash }; } catch (err) { throw new Errors.ContractCallError('Failed to execute depositAndCreateChannel on contract', err); } } async checkpointChannel(params) { const { channelId, candidateState, proofStates = [] } = params; if (!candidateState.sigs || candidateState.sigs.length < 2) { throw new Errors.InvalidParameterError('Candidate state for checkpoint must be signed by both participants.'); } try { return await this.nitroliteService.checkpoint(channelId, candidateState, proofStates); } catch (err) { throw new Errors.ContractCallError('Failed to execute checkpointChannel on contract', err); } } async challengeChannel(params) { const { channelId, candidateState, proofStates = [] } = params; const { challengerSig } = await (0, state_1._prepareAndSignChallengeState)(this.sharedDeps, params); try { return await this.nitroliteService.challenge(channelId, candidateState, proofStates, challengerSig); } catch (err) { throw new Errors.ContractCallError('Failed to execute challengeChannel on contract', err); } } async resizeChannel(params) { const { resizeStateWithSigs, proofs, channelId } = await (0, state_1._prepareAndSignResizeState)(this.sharedDeps, params); try { return await this.nitroliteService.resize(channelId, resizeStateWithSigs, proofs); } catch (err) { throw new Errors.ContractCallError('Failed to execute resizeChannel on contract', err); } } async closeChannel(params) { try { const { finalStateWithSigs, channelId } = await (0, state_1._prepareAndSignFinalState)(this.sharedDeps, params); return await this.nitroliteService.close(channelId, finalStateWithSigs); } catch (err) { throw new Errors.ContractCallError('Failed to execute closeChannel on contract', err); } } async withdrawal(tokenAddress, amount) { try { return await this.nitroliteService.withdraw(tokenAddress, amount); } catch (err) { throw new Errors.ContractCallError('Failed to execute withdrawDeposit on contract', err); } } async getOpenChannels() { try { return await this.nitroliteService.getOpenChannels(this.account.address); } catch (err) { throw err; } } async getAccountBalance(tokenAddress) { try { if (Array.isArray(tokenAddress)) { return await this.nitroliteService.getAccountBalance(this.account.address, tokenAddress); } else { return await this.nitroliteService.getAccountBalance(this.account.address, tokenAddress); } } catch (err) { throw err; } } async getChannelBalance(channelId, tokenAddress) { try { if (Array.isArray(tokenAddress)) { return await this.nitroliteService.getChannelBalance(channelId, tokenAddress); } else { return await this.nitroliteService.getChannelBalance(channelId, tokenAddress); } } catch (err) { throw err; } } async getChannelData(channelId) { try { return await this.nitroliteService.getChannelData(channelId); } catch (err) { throw err; } } async approveTokens(tokenAddress, amount) { const spender = this.addresses.custody; try { return await this.erc20Service.approve(tokenAddress, spender, amount); } catch (err) { throw new Errors.TokenError('Failed to approve tokens', undefined, undefined, undefined, undefined, err); } } async getTokenAllowance(tokenAddress) { const targetOwner = this.account.address; const targetSpender = this.addresses.custody; try { return await this.erc20Service.getTokenAllowance(tokenAddress, targetOwner, targetSpender); } catch (err) { throw new Errors.TokenError('Failed to get token allowance', undefined, undefined, undefined, undefined, err); } } async getTokenBalance(tokenAddress) { const targetAccount = this.account.address; try { return await this.erc20Service.getTokenBalance(tokenAddress, targetAccount); } catch (err) { throw new Errors.TokenError('Failed to get token balance', undefined, undefined, undefined, undefined, err); } } } exports.NitroliteClient = NitroliteClient;