From ed6fe29b7d19d24686f4865df0c2cda16376ad03 Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Thu, 2 Apr 2026 17:41:03 +0300 Subject: [PATCH 01/11] feat: G$ Liquidity Adding Widget. (Ubeswap) --- packages/liquidity-widget/README.md | 97 +++ packages/liquidity-widget/package.json | 26 + .../src/GooddollarLiquidityWidget.ts | 689 ++++++++++++++++++ packages/liquidity-widget/src/index.ts | 1 + .../src/liquidity/components/lw-pool-info.ts | 103 +++ .../liquidity/components/lw-position-card.ts | 179 +++++ .../components/lw-positions-panel.ts | 149 ++++ .../liquidity/components/lw-range-presets.ts | 145 ++++ .../src/liquidity/components/lw-stepper.ts | 112 +++ .../src/liquidity/components/lw-tooltip.ts | 97 +++ .../src/liquidity/components/lw-tx-status.ts | 140 ++++ .../src/liquidity/constants.ts | 152 ++++ .../src/liquidity/pool-service.ts | 167 +++++ .../src/liquidity/tx-service.ts | 166 +++++ .../liquidity-widget/src/liquidity/types.ts | 52 ++ packages/liquidity-widget/tsconfig.json | 12 + .../liquidity-widget/tsup.config.liquidity.ts | 15 + 17 files changed, 2302 insertions(+) create mode 100644 packages/liquidity-widget/README.md create mode 100644 packages/liquidity-widget/package.json create mode 100644 packages/liquidity-widget/src/GooddollarLiquidityWidget.ts create mode 100644 packages/liquidity-widget/src/index.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-position-card.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-stepper.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-tooltip.ts create mode 100644 packages/liquidity-widget/src/liquidity/components/lw-tx-status.ts create mode 100644 packages/liquidity-widget/src/liquidity/constants.ts create mode 100644 packages/liquidity-widget/src/liquidity/pool-service.ts create mode 100644 packages/liquidity-widget/src/liquidity/tx-service.ts create mode 100644 packages/liquidity-widget/src/liquidity/types.ts create mode 100644 packages/liquidity-widget/tsconfig.json create mode 100644 packages/liquidity-widget/tsup.config.liquidity.ts diff --git a/packages/liquidity-widget/README.md b/packages/liquidity-widget/README.md new file mode 100644 index 0000000..d2b6d75 --- /dev/null +++ b/packages/liquidity-widget/README.md @@ -0,0 +1,97 @@ +# Gooddollar Liquidity Web Component + +The `gooddollar-liquidity-widget` web component provides a simple and interactive way for users to provide liquidity to the G$/USDGLO pool on Celo and earn trading fees. + +## Integrating The Component + +Can be used in any website, for a quick setup: + +1. **Download the Script**: Download the `index.global.js` file from the project releases or build it from the source. +2. **Include in HTML**: Add the script to your HTML file. +3. **Add the Component**: Use the `` tag where you want it to appear. + +```html + + + + + + Gooddollar Liquidity + + + + + + + +``` + +## Configurable Options + +Customize the `gooddollar-liquidity-widget` using these properties: + +- **`connectWallet`**: _(Set via JavaScript property)_ + Defines the function called when the "Connect Wallet" button is clicked. + +- **`web3Provider`**: _(Set via JavaScript property)_ + The web3Provider object when the wallet is connected. Wallet connection logic should be handled outside of this component. + +- **`explorerBaseUrl`**: _(String, default: `"https://celoscan.io"`)_ + Base URL used for linking transaction hashes to a block explorer. + +- **`approvalBuffer`**: _(Number, default: `5`)_ + Percentage buffer added on top of the required amount when approving tokens, to account for minor price changes between approval and minting. + +- **`defaultRange`**: _(String, default: `"full"`)_ + The initially selected price range preset. Accepted values: `"full"`, `"wide"`, `"narrow"`. + +- **`showPositions`**: _(Boolean, default: `true`)_ + Whether to show the "My Positions" tab, which lists the user's existing liquidity positions. + +- **`theme`**: _(Object, optional)_ + Override visual styling. Accepts an object with any of the following keys: + - `primaryColor` – accent color for buttons and highlights (CSS color string). + - `borderRadius` – border radius of the widget container (CSS value, e.g. `"12px"`). + - `fontFamily` – font family used by the widget (CSS font-family string). + +## Events + +The widget dispatches custom DOM events that integrators can listen to: + +- **`lw-tx-submitted`** – Fired when a transaction hash is received from the wallet. Detail: `{ hash, step }`. +- **`lw-tx-confirmed`** – Fired when a transaction is confirmed on-chain. Detail: `{ hash, step }`. +- **`lw-tx-failed`** – Fired when a transaction fails. Detail: `{ hash, step, error }`. +- **`lw-position-added`** – Fired after a new liquidity position is successfully minted. Detail: `{ hash }`. + +```js +document.getElementById("liquidityWidget").addEventListener("lw-position-added", (e) => { + console.log("Position minted:", e.detail.hash); +}); +``` diff --git a/packages/liquidity-widget/package.json b/packages/liquidity-widget/package.json new file mode 100644 index 0000000..190efa5 --- /dev/null +++ b/packages/liquidity-widget/package.json @@ -0,0 +1,26 @@ +{ + "name": "@goodsdks/liquidity-widget", + "version": "1.0.0", + "type": "module", + "scripts": { + "build": "yarn build-liquidity-widget", + "dev": "tsc --watch", + "build-liquidity-widget": "tsup --config tsup.config.liquidity.ts", + "bump-liquidity-widget": "yarn version patch && yarn build-liquidity-widget && git add package.json && git commit -m \"version bump\"" + }, + "main": "./dist/index.global.js", + "module": "./dist/index.js", + "devDependencies": { + "@repo/typescript-config": "workspace:*", + "tsup": "^8.3.5", + "typescript": "latest" + }, + "dependencies": { + "lit": "^3.1.0", + "viem": "latest" + }, + "files": [ + "dist", + "src" + ] +} diff --git a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts new file mode 100644 index 0000000..3698897 --- /dev/null +++ b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts @@ -0,0 +1,689 @@ +import { LitElement, html, css, nothing } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { createWalletClient, createPublicClient, custom, http, formatEther, parseEther } from 'viem'; +import type { PublicClient, WalletClient } from 'viem'; +import { celo } from 'viem/chains'; + +import { + GD_TOKEN, USDGLO_TOKEN, IS_GD_TOKEN0, + TICK_SPACING, DEFAULT_EXPLORER_URL, DEFAULT_APPROVAL_BUFFER, + FULL_RANGE_TICK_LOWER, FULL_RANGE_TICK_UPPER, + tickToSqrtPrice, +} from './liquidity/constants'; +import type { TxFlowPhase, TxStepInfo, PositionData, WidgetTheme } from './liquidity/types'; +import { loadPoolData, loadUserBalancesAndAllowances, getUserPositions, formatBigIntDisplay, formatAmount } from './liquidity/pool-service'; +import { approveToken, addLiquidity, parseTxError } from './liquidity/tx-service'; +import { RANGE_PRESETS } from './liquidity/components/lw-range-presets'; + +import './liquidity/components/lw-stepper'; +import './liquidity/components/lw-tooltip'; +import './liquidity/components/lw-range-presets'; +import './liquidity/components/lw-pool-info'; +import './liquidity/components/lw-tx-status'; +import './liquidity/components/lw-position-card'; +import './liquidity/components/lw-positions-panel'; + +type WidgetTab = 'add' | 'positions'; + +@customElement('gooddollar-liquidity-widget') +export class GooddollarLiquidityWidget extends LitElement { + + // ── Integrator Properties ────────────────────────────────────────── + + @property({ type: Object }) + web3Provider: any = null; + + @property({ type: Function }) + connectWallet: (() => void) | undefined = undefined; + + @property({ type: String }) + explorerBaseUrl: string = DEFAULT_EXPLORER_URL; + + @property({ type: Number }) + approvalBuffer: number = DEFAULT_APPROVAL_BUFFER; + + @property({ type: String }) + defaultRange: 'full' | 'wide' | 'narrow' = 'full'; + + @property({ type: Boolean }) + showPositions: boolean = true; + + @property({ type: Object }) + theme: Partial | undefined = undefined; + + // ── Internal State ───────────────────────────────────────────────── + + @state() private activeTab: WidgetTab = 'add'; + @state() private gdInput = ''; + @state() private usdgloInput = ''; + @state() private gdBalance = 0n; + @state() private usdgloBalance = 0n; + @state() private gdAllowance = 0n; + @state() private usdgloAllowance = 0n; + @state() private sqrtPriceX96 = 0n; + @state() private currentTick = 0; + @state() private isLoading = false; + @state() private inputError = ''; + + @state() private selectedRange: 'full' | 'wide' | 'narrow' = 'full'; + @state() private tickLower = FULL_RANGE_TICK_LOWER; + @state() private tickUpper = FULL_RANGE_TICK_UPPER; + + @state() private txPhase: TxFlowPhase = 'idle'; + @state() private txHash = ''; + @state() private txError = ''; + @state() private txSteps: TxStepInfo[] = []; + + @state() private positions: PositionData[] = []; + @state() private positionsLoading = false; + + private walletClient: WalletClient | null = null; + private publicClient: PublicClient | null = null; + private userAddress: string | null = null; + private refreshInterval: ReturnType | null = null; + + // ── Styles ───────────────────────────────────────────────────────── + + static styles = css` + :host { + display: block; + font-family: var(--lw-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif); + max-width: 480px; + margin: 0 auto; + } + + .container { + background: white; + border-radius: var(--lw-radius, 16px); + padding: 24px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + border: 1px solid #e5e7eb; + position: relative; + } + + .header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 8px; + } + + .logo { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; } + .logo img { width: 44px; height: 44px; box-shadow: rgba(0,0,0,0.075) 0px 6px 10px; border-radius: 50%; background: white; } + + .title { font-size: 20px; font-weight: 600; color: #111827; margin: 0; flex: 1; } + .title-row { display: flex; align-items: center; gap: 4px; } + + /* Tabs */ + .tabs { + display: flex; + background: #f3f4f6; + border-radius: 10px; + padding: 3px; + margin-bottom: 16px; + } + .tab { + flex: 1; + text-align: center; + padding: 8px 0; + font-size: 14px; + font-weight: 600; + color: #6b7280; + border-radius: 8px; + border: none; + background: transparent; + cursor: pointer; + transition: all 0.15s; + } + .tab.active { background: white; color: #111827; box-shadow: 0 1px 2px rgba(0,0,0,0.06); } + .tab:hover:not(.active) { color: #374151; } + + /* Input sections */ + .input-section { + background: #f9fafb; + border-radius: 12px; + padding: 16px; + margin-bottom: 12px; + border: 1px solid #e5e7eb; + } + .input-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } + .token-name { font-size: 15px; font-weight: 600; color: #111827; display: flex; align-items: center; } + .balance-info { font-size: 13px; color: #6b7280; } + .input-container { display: flex; align-items: center; gap: 12px; } + .amount-input { + flex: 1; border: none; background: transparent; + font-size: 22px; font-weight: 600; color: #111827; outline: none; + min-width: 0; + } + .max-button { + background: #fff; border-radius: 8px; padding: 5px 10px; + font-size: 12px; font-weight: 500; color: #374151; + border: 1px solid #d1d5db; cursor: pointer; transition: all 0.15s; + } + .max-button:hover { border-color: var(--lw-primary, #00b0ff); color: var(--lw-primary, #00b0ff); } + + /* Buttons */ + .main-button { + width: 100%; + background: var(--lw-primary, #00b0ff); + border: none; + border-radius: 12px; + padding: 14px; + font-size: 16px; + font-weight: 600; + color: #fff; + cursor: pointer; + transition: background 0.15s; + box-shadow: rgba(11,27,102,0.2) 2px 2px 8px -1px; + } + .main-button:hover { filter: brightness(0.92); } + .main-button:disabled { opacity: 0.55; cursor: not-allowed; filter: none; } + + .error-message { color: #dc2626; font-size: 12px; margin-bottom: 12px; text-align: center; } + .hidden { display: none; } + + .overlay { + position: absolute; inset: 0; + background: rgba(255,255,255,0.3); + border-radius: var(--lw-radius, 16px); + z-index: 10; + pointer-events: none; + } + `; + + // ── Lifecycle ────────────────────────────────────────────────────── + + connectedCallback(): void { + super.connectedCallback(); + this.selectedRange = this.defaultRange; + this.refreshInterval = setInterval(() => this.refreshData(), 30_000); + this.refreshData(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + if (this.refreshInterval) clearInterval(this.refreshInterval); + } + + updated(changed: Map) { + if (changed.has('web3Provider')) this.refreshData(); + if (changed.has('theme')) this._applyTheme(); + } + + // ── Render ───────────────────────────────────────────────────────── + + render() { + const isConnected = !!(this.web3Provider && this.web3Provider.isConnected && this.userAddress); + const gdPrice = this._getGdPriceInUsdglo(); + + return html` +
+ +
+ +
+

G$ / USDGLO Liquidity

+ +
+
+ + + + + + ${this.showPositions && isConnected ? html` +
+ + +
+ ` : nothing} + + + ${this.activeTab === 'add' ? this._renderAddTab(isConnected) : this._renderPositionsTab()} + + ${this.txPhase !== 'idle' && this.txPhase !== 'success' && this.txPhase !== 'error' + ? html`
` : nothing} +
+ `; + } + + private _renderAddTab(isConnected: boolean) { + const showStepper = this.txPhase !== 'idle' && this.txSteps.length > 0; + + return html` + + + + +
+
+ + G$ + + + + Balance: ${this.isLoading ? 'Loading...' : formatBigIntDisplay(this.gdBalance)} + +
+
+ + +
+
+ + +
+
+ + USDGLO + + + + Balance: ${this.isLoading ? 'Loading...' : formatBigIntDisplay(this.usdgloBalance)} + +
+
+ + +
+
+ + ${this.inputError ? html`
${this.inputError}
` : nothing} + + + + + + ${showStepper ? html`` : nothing} + + + ${!isConnected + ? html`` + : html` + + ` + } + `; + } + + private _renderPositionsTab() { + return html` + + `; + } + + // ── Theme ────────────────────────────────────────────────────────── + + private _applyTheme() { + if (!this.theme) return; + if (this.theme.primaryColor) + this.style.setProperty('--lw-primary', this.theme.primaryColor); + if (this.theme.borderRadius) + this.style.setProperty('--lw-radius', this.theme.borderRadius); + if (this.theme.fontFamily) + this.style.setProperty('--lw-font', this.theme.fontFamily); + } + + // ── Data Loading ─────────────────────────────────────────────────── + + private async refreshData() { + if (!this.publicClient) { + this.publicClient = createPublicClient({ + chain: celo, + transport: http(), + }) as unknown as PublicClient; + } + + this.isLoading = true; + + try { + const pool = await loadPoolData(this.publicClient); + this.sqrtPriceX96 = pool.sqrtPriceX96; + this.currentTick = pool.currentTick; + } catch (e) { + console.error('Error loading pool data:', e); + } + + try { + if (this.web3Provider && this.web3Provider.isConnected) { + this.walletClient = createWalletClient({ chain: celo, transport: custom(this.web3Provider) }); + const accounts = await this.web3Provider.request({ method: 'eth_accounts' }); + if (accounts.length > 0) { + this.userAddress = accounts[0]; + const data = await loadUserBalancesAndAllowances(this.publicClient, this.userAddress as `0x${string}`); + this.gdBalance = data.gdBalance; + this.usdgloBalance = data.usdgloBalance; + this.gdAllowance = data.gdAllowance; + this.usdgloAllowance = data.usdgloAllowance; + } else { + this._resetUserData(); + } + } else { + this._resetUserData(); + } + } catch (e) { + console.error('Error loading user data:', e); + } + + this.isLoading = false; + } + + private _resetUserData() { + this.userAddress = null; + this.gdBalance = 0n; + this.usdgloBalance = 0n; + this.gdAllowance = 0n; + this.usdgloAllowance = 0n; + this.positions = []; + } + + private async _loadPositions() { + if (!this.publicClient || !this.userAddress) return; + this.positionsLoading = true; + try { + this.positions = await getUserPositions( + this.publicClient, + this.userAddress as `0x${string}`, + this.currentTick, + ); + } catch (e) { + console.error('Error loading positions:', e); + } + this.positionsLoading = false; + } + + // ── Price & Amount Math ──────────────────────────────────────────── + + private _getGdPriceInUsdglo(): number { + if (this.sqrtPriceX96 === 0n) return 0; + const sqrtPrice = Number(this.sqrtPriceX96) / (2 ** 96); + const rawPrice = sqrtPrice * sqrtPrice; + return IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice; + } + + private _getSqrtPriceFloat(): number { + return Number(this.sqrtPriceX96) / (2 ** 96); + } + + private _calcAmount1From0(amount0: number): number { + const sqC = this._getSqrtPriceFloat(); + const sqL = tickToSqrtPrice(this.tickLower); + const sqU = tickToSqrtPrice(this.tickUpper); + if (sqU <= sqL || sqC <= sqL || sqC >= sqU) return 0; + const L = amount0 * sqC * sqU / (sqU - sqC); + return L * (sqC - sqL); + } + + private _calcAmount0From1(amount1: number): number { + const sqC = this._getSqrtPriceFloat(); + const sqL = tickToSqrtPrice(this.tickLower); + const sqU = tickToSqrtPrice(this.tickUpper); + if (sqU <= sqL || sqC >= sqU || sqC <= sqL) return 0; + const L = amount1 / (sqC - sqL); + return L * (sqU - sqC) / (sqC * sqU); + } + + private _calcUsdgloFromGd() { + const gd = parseFloat(this.gdInput); + if (isNaN(gd) || gd <= 0 || this.sqrtPriceX96 === 0n) { this.usdgloInput = ''; return; } + const usdglo = IS_GD_TOKEN0 ? this._calcAmount1From0(gd) : this._calcAmount0From1(gd); + if (isFinite(usdglo) && usdglo >= 0) this.usdgloInput = formatAmount(usdglo); + } + + private _calcGdFromUsdglo() { + const u = parseFloat(this.usdgloInput); + if (isNaN(u) || u <= 0 || this.sqrtPriceX96 === 0n) { this.gdInput = ''; return; } + const gd = IS_GD_TOKEN0 ? this._calcAmount0From1(u) : this._calcAmount1From0(u); + if (isFinite(gd) && gd >= 0) this.gdInput = formatAmount(gd); + } + + private _safeParseEther(value: string): bigint { + try { + if (!value || value.trim() === '' || value === '.') return 0n; + return parseEther(value); + } catch { return 0n; } + } + + // ── Validation ───────────────────────────────────────────────────── + + private _validateInputs(force = false) { + this.inputError = ''; + const re = /^[0-9]*\.?[0-9]*$/; + if (this.gdInput && !re.test(this.gdInput)) { this.inputError = 'Invalid G$ value'; return; } + if (this.usdgloInput && !re.test(this.usdgloInput)) { this.inputError = 'Invalid USDGLO value'; return; } + + const gdNum = parseFloat(this.gdInput || '0'); + const usdgloNum = parseFloat(this.usdgloInput || '0'); + + if (force && (isNaN(gdNum) || gdNum <= 0 || isNaN(usdgloNum) || usdgloNum <= 0)) { + this.inputError = 'Please enter valid amounts'; + return; + } + if (gdNum > 0 && this._safeParseEther(this.gdInput) > this.gdBalance) { + this.inputError = 'Insufficient G$ balance'; + return; + } + if (usdgloNum > 0 && this._safeParseEther(this.usdgloInput) > this.usdgloBalance) { + this.inputError = 'Insufficient USDGLO balance'; + return; + } + } + + private _getButtonLabel(): string { + if (this.txPhase === 'success') return 'Add More Liquidity'; + + const gdWei = this._safeParseEther(this.gdInput); + const usdgloWei = this._safeParseEther(this.usdgloInput); + + if (gdWei > 0n && this.gdAllowance < gdWei) return 'Approve & Add Liquidity'; + if (usdgloWei > 0n && this.usdgloAllowance < usdgloWei) return 'Approve & Add Liquidity'; + return 'Add Liquidity'; + } + + // ── Event Handlers ───────────────────────────────────────────────── + + private _handleConnect() { this.connectWallet?.(); } + + private _handleGdInput(e: Event) { + this.gdInput = (e.target as HTMLInputElement).value; + this._calcUsdgloFromGd(); + this._validateInputs(); + } + + private _handleUsdgloInput(e: Event) { + this.usdgloInput = (e.target as HTMLInputElement).value; + this._calcGdFromUsdglo(); + this._validateInputs(); + } + + private _handleGdMax() { + this.gdInput = Number(formatEther(this.gdBalance)).toString(); + this._calcUsdgloFromGd(); + this.inputError = ''; + } + + private _handleUsdgloMax() { + this.usdgloInput = Number(formatEther(this.usdgloBalance)).toString(); + this._calcGdFromUsdglo(); + this.inputError = ''; + } + + private _onRangeChange(e: CustomEvent) { + const id = e.detail.id as 'full' | 'wide' | 'narrow'; + this.selectedRange = id; + const preset = RANGE_PRESETS.find(p => p.id === id)!; + const { tickLower, tickUpper } = preset.getTickRange(this.currentTick, TICK_SPACING); + this.tickLower = tickLower; + this.tickUpper = tickUpper; + this._calcUsdgloFromGd(); + } + + private _handleRetry() { + this.txPhase = 'idle'; + this.txHash = ''; + this.txError = ''; + this.txSteps = []; + } + + // ── Main Transaction Flow ────────────────────────────────────────── + + async _handleMainAction() { + if (!this.walletClient || !this.publicClient || !this.userAddress) return; + + if (this.txPhase === 'success') { + this.txPhase = 'idle'; + this.txHash = ''; + this.txSteps = []; + return; + } + + this._validateInputs(true); + if (this.inputError) return; + + const account = this.userAddress as `0x${string}`; + const gdWei = this._safeParseEther(this.gdInput); + const usdgloWei = this._safeParseEther(this.usdgloInput); + + const needGdApproval = gdWei > 0n && this.gdAllowance < gdWei; + const needUsdgloApproval = usdgloWei > 0n && this.usdgloAllowance < usdgloWei; + + const steps: TxStepInfo[] = [ + { label: 'Approve G$', status: needGdApproval ? 'pending' : 'skipped' }, + { label: 'Approve USDGLO', status: needUsdgloApproval ? 'pending' : 'skipped' }, + { label: 'Add Liquidity', status: 'pending' }, + ]; + this.txSteps = [...steps]; + this.txError = ''; + + try { + // Step 1: Approve G$ + if (needGdApproval) { + steps[0].status = 'active'; + this.txSteps = [...steps]; + this.txPhase = 'approving-gd'; + this.txHash = ''; + + const hash = await approveToken( + this.publicClient, this.walletClient, account, + GD_TOKEN, gdWei, this.approvalBuffer, + { + onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-gd'); }, + onConfirmed: (h) => this._emitTxEvent('lw-tx-confirmed', h, 'approve-gd'), + }, + ); + + steps[0].status = 'completed'; + steps[0].txHash = hash; + this.txSteps = [...steps]; + await this.refreshData(); + } + + // Step 2: Approve USDGLO + if (needUsdgloApproval) { + steps[1].status = 'active'; + this.txSteps = [...steps]; + this.txPhase = 'approving-usdglo'; + this.txHash = ''; + + const hash = await approveToken( + this.publicClient, this.walletClient, account, + USDGLO_TOKEN, usdgloWei, this.approvalBuffer, + { + onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-usdglo'); }, + onConfirmed: (h) => this._emitTxEvent('lw-tx-confirmed', h, 'approve-usdglo'), + }, + ); + + steps[1].status = 'completed'; + steps[1].txHash = hash; + this.txSteps = [...steps]; + await this.refreshData(); + } + + // Step 3: Mint + steps[2].status = 'active'; + this.txSteps = [...steps]; + this.txPhase = 'minting'; + this.txHash = ''; + + const hash = await addLiquidity( + this.publicClient, this.walletClient, account, + gdWei, usdgloWei, this.tickLower, this.tickUpper, + { + onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'mint'); }, + onConfirmed: (h) => this._emitTxEvent('lw-tx-confirmed', h, 'mint'), + }, + ); + + steps[2].status = 'completed'; + steps[2].txHash = hash; + this.txSteps = [...steps]; + this.txPhase = 'success'; + this.txHash = hash; + + this._emitEvent('lw-position-added', { hash }); + + this.gdInput = ''; + this.usdgloInput = ''; + this.inputError = ''; + await this.refreshData(); + + } catch (error: any) { + this.txPhase = 'error'; + this.txError = parseTxError(error); + this._emitTxEvent('lw-tx-failed', this.txHash, this.txPhase, error); + } + } + + // ── Custom Events for Integrators ────────────────────────────────── + + private _emitEvent(name: string, detail: Record) { + this.dispatchEvent(new CustomEvent(name, { + detail, bubbles: true, composed: true, + })); + } + + private _emitTxEvent(name: string, hash: string, step: string, error?: any) { + this._emitEvent(name, { hash, step, ...(error ? { error: parseTxError(error) } : {}) }); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'gooddollar-liquidity-widget': GooddollarLiquidityWidget; + } +} diff --git a/packages/liquidity-widget/src/index.ts b/packages/liquidity-widget/src/index.ts new file mode 100644 index 0000000..f2c6997 --- /dev/null +++ b/packages/liquidity-widget/src/index.ts @@ -0,0 +1 @@ +export * from "./GooddollarLiquidityWidget" diff --git a/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts b/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts new file mode 100644 index 0000000..648c4ad --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts @@ -0,0 +1,103 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { POOL_ADDRESS, POOL_FEE } from '../constants'; + +import './lw-tooltip'; + +@customElement('lw-pool-info') +export class LwPoolInfo extends LitElement { + static styles = css` + :host { display: block; margin-bottom: 16px; } + + .pool-info { + background: #f0f9ff; + border: 1px solid #bae6fd; + border-radius: 10px; + padding: 12px 14px; + display: flex; + flex-wrap: wrap; + gap: 12px; + align-items: center; + justify-content: space-between; + } + + .info-item { + display: flex; + flex-direction: column; + gap: 2px; + } + + .info-label { + font-size: 11px; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.03em; + display: flex; + align-items: center; + } + + .info-value { + font-size: 14px; + font-weight: 600; + color: #111827; + } + + .pool-link { + font-size: 12px; + color: var(--lw-primary, #00b0ff); + text-decoration: none; + font-weight: 500; + } + .pool-link:hover { text-decoration: underline; } + `; + + @property({ type: Number }) + gdPrice: number = 0; + + @property({ type: Boolean }) + loading: boolean = false; + + @property({ type: String }) + explorerUrl: string = 'https://celoscan.io'; + + render() { + const feeTier = `${POOL_FEE / 10_000}%`; + const priceDisplay = this.loading + ? 'Loading...' + : this.gdPrice > 0 + ? `${(1000 * this.gdPrice).toFixed(4)} USDGLO` + : '...'; + + return html` +
+
+ Pool + + + G$ / USDGLO +
+
+ Fee Tier + ${feeTier} +
+
+ Price (1,000 G$) + ${priceDisplay} +
+ +
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-pool-info': LwPoolInfo; + } +} diff --git a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts new file mode 100644 index 0000000..111fd67 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts @@ -0,0 +1,179 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { formatEther } from 'viem'; +import type { PositionData } from '../types'; +import { IS_GD_TOKEN0 } from '../constants'; + +const UBESWAP_POOL_BASE = 'https://app.ubeswap.org/#/pools'; + +@customElement('lw-position-card') +export class LwPositionCard extends LitElement { + static styles = css` + :host { display: block; } + + .card { + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 10px; + padding: 14px; + margin-bottom: 10px; + transition: border-color 0.15s; + } + .card:hover { border-color: #d1d5db; } + + .card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; + } + + .token-id { + font-size: 12px; + color: #6b7280; + font-weight: 500; + } + + .range-badge { + font-size: 11px; + font-weight: 600; + padding: 2px 8px; + border-radius: 12px; + } + .range-badge.in-range { background: #d1fae5; color: #065f46; } + .range-badge.out-of-range { background: #fef3c7; color: #92400e; } + + .amounts { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + margin-bottom: 10px; + } + + .amount-item { + display: flex; + flex-direction: column; + gap: 1px; + } + .amount-label { + font-size: 11px; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.03em; + } + .amount-value { + font-size: 14px; + font-weight: 600; + color: #111827; + } + + .fees-row { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: 8px; + border-top: 1px solid #e5e7eb; + } + .fees-label { + font-size: 12px; + color: #6b7280; + } + .fees-value { + font-size: 13px; + font-weight: 600; + color: #059669; + } + + .actions { + display: flex; + gap: 8px; + margin-top: 10px; + } + + .manage-link { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + border-radius: 8px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + text-decoration: none; + transition: background 0.15s; + background: var(--lw-primary, #00b0ff); + color: white; + } + .manage-link:hover { filter: brightness(0.92); } + .manage-link .arrow { margin-left: 6px; font-size: 14px; } + `; + + @property({ type: Object }) + position!: PositionData; + + @property({ type: String }) + explorerUrl: string = 'https://celoscan.io'; + + private _fmt(val: bigint): string { + const n = Number(formatEther(val)); + if (n === 0) return '0'; + if (n < 0.0001) return '<0.0001'; + return Intl.NumberFormat(undefined, { maximumFractionDigits: 4 }).format(n); + } + + render() { + const p = this.position; + if (!p) return html``; + + const gdAmount = IS_GD_TOKEN0 ? p.amount0 : p.amount1; + const usdgloAmount = IS_GD_TOKEN0 ? p.amount1 : p.amount0; + const gdFees = IS_GD_TOKEN0 ? p.tokensOwed0 : p.tokensOwed1; + const usdgloFees = IS_GD_TOKEN0 ? p.tokensOwed1 : p.tokensOwed0; + const manageUrl = `${UBESWAP_POOL_BASE}/${p.tokenId.toString()}`; + + return html` +
+
+ Position #${p.tokenId.toString()} + + ${p.inRange ? 'In Range' : 'Out of Range'} + +
+ +
+
+ G$ + ${this._fmt(gdAmount)} +
+
+ USDGLO + ${this._fmt(usdgloAmount)} +
+
+ +
+ Unclaimed Fees + + ${this._fmt(gdFees)} G$ / ${this._fmt(usdgloFees)} USDGLO + +
+ + +
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-position-card': LwPositionCard; + } +} diff --git a/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts b/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts new file mode 100644 index 0000000..ee9a131 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts @@ -0,0 +1,149 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { formatEther } from 'viem'; +import type { PositionData } from '../types'; +import { IS_GD_TOKEN0 } from '../constants'; + +import './lw-position-card'; +import './lw-tooltip'; + +@customElement('lw-positions-panel') +export class LwPositionsPanel extends LitElement { + static styles = css` + :host { display: block; } + + .header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 14px; + } + + .header-title { + font-size: 16px; + font-weight: 600; + color: #111827; + display: flex; + align-items: center; + } + + .count-badge { + font-size: 11px; + font-weight: 600; + background: var(--lw-primary, #00b0ff); + color: white; + border-radius: 10px; + padding: 1px 7px; + margin-left: 8px; + } + + .summary { + background: #f0fdf4; + border: 1px solid #bbf7d0; + border-radius: 10px; + padding: 12px 14px; + margin-bottom: 14px; + display: flex; + gap: 16px; + flex-wrap: wrap; + } + + .summary-item { + display: flex; + flex-direction: column; + gap: 1px; + } + .summary-label { font-size: 11px; color: #6b7280; text-transform: uppercase; letter-spacing: 0.03em; } + .summary-value { font-size: 14px; font-weight: 600; color: #065f46; } + + .empty { + text-align: center; + color: #9ca3af; + font-size: 14px; + padding: 24px 0; + } + + .loading { + text-align: center; + color: #6b7280; + font-size: 14px; + padding: 24px 0; + } + `; + + @property({ type: Array }) + positions: PositionData[] = []; + + @property({ type: Boolean }) + loading: boolean = false; + + @property({ type: String }) + explorerUrl: string = 'https://celoscan.io'; + + private _fmt(val: bigint): string { + const n = Number(formatEther(val)); + if (n === 0) return '0'; + return Intl.NumberFormat(undefined, { maximumFractionDigits: 4 }).format(n); + } + + render() { + if (this.loading) { + return html`
Loading positions...
`; + } + + const totalGd = this.positions.reduce((sum, p) => + sum + (IS_GD_TOKEN0 ? p.amount0 : p.amount1), 0n); + const totalUsdglo = this.positions.reduce((sum, p) => + sum + (IS_GD_TOKEN0 ? p.amount1 : p.amount0), 0n); + const totalGdFees = this.positions.reduce((sum, p) => + sum + (IS_GD_TOKEN0 ? p.tokensOwed0 : p.tokensOwed1), 0n); + const totalUsdgloFees = this.positions.reduce((sum, p) => + sum + (IS_GD_TOKEN0 ? p.tokensOwed1 : p.tokensOwed0), 0n); + + return html` +
+ + My Positions + + ${this.positions.length > 0 ? html`${this.positions.length}` : ''} + +
+ + ${this.positions.length === 0 ? html` +
No open positions in this pool.
+ ` : html` +
+
+ Total G$ + ${this._fmt(totalGd)} +
+
+ Total USDGLO + ${this._fmt(totalUsdglo)} +
+
+ Unclaimed G$ Fees + ${this._fmt(totalGdFees)} +
+
+ Unclaimed USDGLO Fees + ${this._fmt(totalUsdgloFees)} +
+
+ + ${this.positions.map(p => html` + + `)} + `} + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-positions-panel': LwPositionsPanel; + } +} diff --git a/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts b/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts new file mode 100644 index 0000000..f3db142 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts @@ -0,0 +1,145 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import type { RangePreset } from '../types'; +import { + FULL_RANGE_TICK_LOWER, FULL_RANGE_TICK_UPPER, TICK_SPACING, + POOL_FEE, nearestUsableTick, +} from '../constants'; + +import './lw-tooltip'; + +export const RANGE_PRESETS: RangePreset[] = [ + { + id: 'full', + label: 'Full Range', + description: 'Max flexibility, lower capital efficiency', + tooltip: 'Covers the entire price range. Your liquidity is always active but spread thin, earning lower fees per dollar deposited.', + concentrationMultiplier: 1, + getTickRange: () => ({ + tickLower: FULL_RANGE_TICK_LOWER, + tickUpper: FULL_RANGE_TICK_UPPER, + }), + }, + { + id: 'wide', + label: 'Wide', + description: 'Balanced range around current price', + tooltip: 'Concentrates liquidity in a wide band around the current price. Good balance of fee earnings and rebalancing frequency.', + concentrationMultiplier: 4, + getTickRange: (currentTick: number, tickSpacing: number) => ({ + tickLower: nearestUsableTick(currentTick - 120 * tickSpacing, tickSpacing), + tickUpper: nearestUsableTick(currentTick + 120 * tickSpacing, tickSpacing), + }), + }, + { + id: 'narrow', + label: 'Narrow', + description: 'Tight range, higher yield, more risk', + tooltip: 'Concentrates liquidity tightly around the current price for maximum fee earnings. Higher impermanent loss risk and may go out of range if price moves significantly.', + concentrationMultiplier: 10, + getTickRange: (currentTick: number, tickSpacing: number) => ({ + tickLower: nearestUsableTick(currentTick - 30 * tickSpacing, tickSpacing), + tickUpper: nearestUsableTick(currentTick + 30 * tickSpacing, tickSpacing), + }), + }, +]; + +@customElement('lw-range-presets') +export class LwRangePresets extends LitElement { + static styles = css` + :host { display: block; margin-bottom: 16px; } + + .label { + font-size: 13px; + font-weight: 600; + color: #374151; + margin-bottom: 8px; + display: flex; + align-items: center; + } + + .presets { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + } + + .preset-card { + background: #f9fafb; + border: 2px solid #e5e7eb; + border-radius: 10px; + padding: 10px 8px; + cursor: pointer; + text-align: center; + transition: border-color 0.15s, background 0.15s; + } + .preset-card:hover { border-color: #d1d5db; } + .preset-card.selected { + border-color: var(--lw-primary, #00b0ff); + background: rgba(0, 176, 255, 0.06); + } + + .preset-name { + font-size: 13px; + font-weight: 600; + color: #111827; + margin-bottom: 2px; + } + + .preset-desc { + font-size: 11px; + color: #6b7280; + line-height: 1.3; + margin-bottom: 4px; + } + + .preset-yield { + font-size: 12px; + font-weight: 600; + color: #059669; + } + `; + + @property({ type: String }) + selected: 'full' | 'wide' | 'narrow' = 'full'; + + @property({ type: Number }) + baseApr: number = 0; + + render() { + return html` +
+ Range Strategy + +
+
+ ${RANGE_PRESETS.map(preset => html` +
this._select(preset.id)} + > +
${preset.label}
+
${preset.description}
+ ${this.baseApr > 0 ? html` +
~${(this.baseApr * preset.concentrationMultiplier).toFixed(1)}% APR
+ ` : ''} +
+ `)} +
+ `; + } + + private _select(id: 'full' | 'wide' | 'narrow') { + this.selected = id; + this.dispatchEvent(new CustomEvent('range-change', { + detail: { id }, + bubbles: true, composed: true, + })); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-range-presets': LwRangePresets; + } +} diff --git a/packages/liquidity-widget/src/liquidity/components/lw-stepper.ts b/packages/liquidity-widget/src/liquidity/components/lw-stepper.ts new file mode 100644 index 0000000..9680d04 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-stepper.ts @@ -0,0 +1,112 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import type { TxStepInfo } from '../types'; + +@customElement('lw-stepper') +export class LwStepper extends LitElement { + static styles = css` + :host { display: block; margin-bottom: 16px; } + + .stepper { + display: flex; + align-items: center; + justify-content: center; + gap: 0; + padding: 12px 0; + } + + .step { + display: flex; + align-items: center; + gap: 6px; + font-size: 13px; + color: #9ca3af; + white-space: nowrap; + } + + .step.active { color: var(--lw-primary, #00b0ff); font-weight: 600; } + .step.completed { color: #10b981; } + .step.skipped { color: #d1d5db; text-decoration: line-through; } + + .step-circle { + width: 24px; + height: 24px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + font-weight: 600; + flex-shrink: 0; + border: 2px solid #e5e7eb; + background: white; + color: #9ca3af; + } + + .step.active .step-circle { + border-color: var(--lw-primary, #00b0ff); + background: var(--lw-primary, #00b0ff); + color: white; + } + + .step.completed .step-circle { + border-color: #10b981; + background: #10b981; + color: white; + } + + .step.skipped .step-circle { + border-color: #e5e7eb; + background: #f3f4f6; + color: #d1d5db; + } + + .connector { + width: 32px; + height: 2px; + background: #e5e7eb; + margin: 0 4px; + flex-shrink: 0; + } + + .connector.done { background: #10b981; } + + @keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } + } + .step.active .step-circle { animation: pulse 1.5s ease-in-out infinite; } + `; + + @property({ type: Array }) + steps: TxStepInfo[] = []; + + render() { + return html` +
+ ${this.steps.map((step, i) => html` + ${i > 0 ? html`
` : ''} +
+
+ ${step.status === 'completed' ? html`✓` : + step.status === 'skipped' ? html`—` : + html`${i + 1}`} +
+ ${step.label} +
+ `)} +
+ `; + } + + private _connectorDone(index: number): boolean { + const prev = this.steps[index - 1]; + return prev?.status === 'completed' || prev?.status === 'skipped'; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-stepper': LwStepper; + } +} diff --git a/packages/liquidity-widget/src/liquidity/components/lw-tooltip.ts b/packages/liquidity-widget/src/liquidity/components/lw-tooltip.ts new file mode 100644 index 0000000..529a3ac --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-tooltip.ts @@ -0,0 +1,97 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; + +@customElement('lw-tooltip') +export class LwTooltip extends LitElement { + static styles = css` + :host { + display: inline-flex; + position: relative; + vertical-align: middle; + } + + .trigger { + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + border-radius: 50%; + background: #e5e7eb; + color: #6b7280; + font-size: 10px; + font-weight: 700; + line-height: 1; + border: none; + padding: 0; + margin-left: 4px; + transition: background 0.15s; + } + .trigger:hover { background: #d1d5db; } + + .popover { + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + background: #1f2937; + color: #f9fafb; + font-size: 12px; + line-height: 1.5; + padding: 8px 12px; + border-radius: 8px; + width: max-content; + max-width: 260px; + z-index: 100; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + pointer-events: none; + opacity: 0; + transition: opacity 0.15s; + } + + .popover.visible { + opacity: 1; + pointer-events: auto; + } + + .popover::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + border: 6px solid transparent; + border-top-color: #1f2937; + } + `; + + @property({ type: String }) + text = ''; + + @state() + private _visible = false; + + render() { + return html` + +
${this.text}
+ `; + } + + private _show() { this._visible = true; } + private _hide() { this._visible = false; } + private _toggle() { this._visible = !this._visible; } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-tooltip': LwTooltip; + } +} diff --git a/packages/liquidity-widget/src/liquidity/components/lw-tx-status.ts b/packages/liquidity-widget/src/liquidity/components/lw-tx-status.ts new file mode 100644 index 0000000..2e36225 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/components/lw-tx-status.ts @@ -0,0 +1,140 @@ +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import type { TxFlowPhase } from '../types'; + +@customElement('lw-tx-status') +export class LwTxStatus extends LitElement { + static styles = css` + :host { display: block; margin-bottom: 12px; } + + .status-banner { + border-radius: 10px; + padding: 12px 14px; + font-size: 13px; + line-height: 1.5; + display: flex; + align-items: flex-start; + gap: 10px; + } + + .status-banner.info { + background: #eff6ff; + border: 1px solid #bfdbfe; + color: #1e40af; + } + .status-banner.success { + background: #ecfdf5; + border: 1px solid #a7f3d0; + color: #065f46; + } + .status-banner.error { + background: #fef2f2; + border: 1px solid #fecaca; + color: #991b1b; + } + + .status-icon { font-size: 16px; flex-shrink: 0; margin-top: 1px; } + .status-body { flex: 1; } + .status-body a { + color: inherit; + font-weight: 600; + text-decoration: underline; + } + + .retry-btn { + margin-top: 8px; + background: #991b1b; + color: white; + border: none; + border-radius: 6px; + padding: 6px 14px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + } + .retry-btn:hover { background: #7f1d1d; } + + @keyframes spin { + to { transform: rotate(360deg); } + } + .spinner { + width: 16px; + height: 16px; + border: 2px solid #bfdbfe; + border-top-color: #1e40af; + border-radius: 50%; + animation: spin 0.8s linear infinite; + flex-shrink: 0; + margin-top: 1px; + } + `; + + @property({ type: String }) + phase: TxFlowPhase = 'idle'; + + @property({ type: String }) + txHash: string = ''; + + @property({ type: String }) + errorMessage: string = ''; + + @property({ type: String }) + explorerUrl: string = 'https://celoscan.io'; + + render() { + if (this.phase === 'idle') return html``; + + if (this.phase === 'error') { + return html` +
+ +
+ ${this.errorMessage || 'Transaction failed.'} +
+ +
+
+ `; + } + + if (this.phase === 'success') { + return html` +
+ +
+ Liquidity added successfully! + ${this.txHash ? html` +
View on Explorer + ` : ''} +
+
+ `; + } + + const stepLabel = this.phase === 'approving-gd' ? 'Approving G$...' + : this.phase === 'approving-usdglo' ? 'Approving USDGLO...' + : 'Adding liquidity...'; + + return html` +
+
+
+ ${stepLabel} + ${this.txHash ? html` +
View transaction + ` : ''} +
+
+ `; + } + + private _retry() { + this.dispatchEvent(new CustomEvent('retry', { bubbles: true, composed: true })); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'lw-tx-status': LwTxStatus; + } +} diff --git a/packages/liquidity-widget/src/liquidity/constants.ts b/packages/liquidity-widget/src/liquidity/constants.ts new file mode 100644 index 0000000..1a9f991 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/constants.ts @@ -0,0 +1,152 @@ +import { parseAbi } from 'viem'; + +export const GD_TOKEN = '0x62B8B11039FcfE5aB0C56E502b1C372A3d2a9c7A' as const; +export const USDGLO_TOKEN = '0x4F604735c1cF31399C6E711D5962b2B3E0225AD3' as const; +export const POSITION_MANAGER = '0x897387c7B996485c3AAa85c94272Cd6C506f8c8F' as const; +export const POOL_ADDRESS = '0x3D9e27C04076288eBfdC4815b4f6d81b0ED1b341' as const; +export const POOL_FEE = 10_000; +export const TICK_SPACING = 200; +export const DEFAULT_EXPLORER_URL = 'https://celoscan.io'; +export const DEFAULT_APPROVAL_BUFFER = 5; + +export const IS_GD_TOKEN0 = GD_TOKEN.toLowerCase() < USDGLO_TOKEN.toLowerCase(); +export const TOKEN0 = IS_GD_TOKEN0 ? GD_TOKEN : USDGLO_TOKEN; +export const TOKEN1 = IS_GD_TOKEN0 ? USDGLO_TOKEN : GD_TOKEN; + +export const FULL_RANGE_TICK_LOWER = -887_200; +export const FULL_RANGE_TICK_UPPER = 887_200; + +export const ERC20_ABI = parseAbi([ + 'function balanceOf(address account) view returns (uint256)', + 'function allowance(address owner, address spender) view returns (uint256)', + 'function approve(address spender, uint256 amount) returns (bool)', +]); + +export const POOL_ABI = parseAbi([ + 'function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)', +]); + +export const POSITION_MANAGER_ABI = [ + { + inputs: [ + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + { internalType: 'uint24', name: 'fee', type: 'uint24' }, + { internalType: 'int24', name: 'tickLower', type: 'int24' }, + { internalType: 'int24', name: 'tickUpper', type: 'int24' }, + { internalType: 'uint256', name: 'amount0Desired', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1Desired', type: 'uint256' }, + { internalType: 'uint256', name: 'amount0Min', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1Min', type: 'uint256' }, + { internalType: 'address', name: 'recipient', type: 'address' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + ], + internalType: 'struct INonfungiblePositionManager.MintParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'mint', + outputs: [ + { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, + { internalType: 'uint128', name: 'liquidity', type: 'uint128' }, + { internalType: 'uint256', name: 'amount0', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'owner', type: 'address' }], + name: 'balanceOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'uint256', name: 'index', type: 'uint256' }, + ], + name: 'tokenOfOwnerByIndex', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], + name: 'positions', + outputs: [ + { internalType: 'uint96', name: 'nonce', type: 'uint96' }, + { internalType: 'address', name: 'operator', type: 'address' }, + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + { internalType: 'uint24', name: 'fee', type: 'uint24' }, + { internalType: 'int24', name: 'tickLower', type: 'int24' }, + { internalType: 'int24', name: 'tickUpper', type: 'int24' }, + { internalType: 'uint128', name: 'liquidity', type: 'uint128' }, + { internalType: 'uint256', name: 'feeGrowthInside0LastX128', type: 'uint256' }, + { internalType: 'uint256', name: 'feeGrowthInside1LastX128', type: 'uint256' }, + { internalType: 'uint128', name: 'tokensOwed0', type: 'uint128' }, + { internalType: 'uint128', name: 'tokensOwed1', type: 'uint128' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, + { internalType: 'uint128', name: 'liquidity', type: 'uint128' }, + { internalType: 'uint256', name: 'amount0Min', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1Min', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + ], + internalType: 'struct INonfungiblePositionManager.DecreaseLiquidityParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'decreaseLiquidity', + outputs: [ + { internalType: 'uint256', name: 'amount0', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, + { internalType: 'address', name: 'recipient', type: 'address' }, + { internalType: 'uint128', name: 'amount0Max', type: 'uint128' }, + { internalType: 'uint128', name: 'amount1Max', type: 'uint128' }, + ], + internalType: 'struct INonfungiblePositionManager.CollectParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'collect', + outputs: [ + { internalType: 'uint256', name: 'amount0', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, +] as const; + +export function tickToSqrtPrice(tick: number): number { + return Math.sqrt(1.0001 ** tick); +} + +export function nearestUsableTick(tick: number, spacing: number): number { + const rounded = Math.round(tick / spacing) * spacing; + return rounded; +} diff --git a/packages/liquidity-widget/src/liquidity/pool-service.ts b/packages/liquidity-widget/src/liquidity/pool-service.ts new file mode 100644 index 0000000..5eecb10 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/pool-service.ts @@ -0,0 +1,167 @@ +import type { PublicClient } from 'viem'; +import { formatEther } from 'viem'; +import { + POOL_ADDRESS, POOL_ABI, POSITION_MANAGER, POSITION_MANAGER_ABI, + GD_TOKEN, USDGLO_TOKEN, POOL_FEE, IS_GD_TOKEN0, TOKEN0, TOKEN1, + tickToSqrtPrice, +} from './constants'; +import type { PoolData, PositionData } from './types'; + +export async function loadPoolData(publicClient: PublicClient): Promise { + const slot0 = await publicClient.readContract({ + address: POOL_ADDRESS, + abi: POOL_ABI, + functionName: 'slot0', + }); + + const sqrtPriceX96 = slot0[0]; + const currentTick = slot0[1]; + const sqrtPrice = Number(sqrtPriceX96) / (2 ** 96); + const rawPrice = sqrtPrice * sqrtPrice; + const gdPriceInUsdglo = rawPrice === 0 ? 0 : (IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice); + + return { sqrtPriceX96, currentTick, price: rawPrice, gdPriceInUsdglo }; +} + +export async function loadUserBalancesAndAllowances( + publicClient: PublicClient, + userAddress: `0x${string}`, +) { + const [gdBalance, usdgloBalance, gdAllowance, usdgloAllowance] = await Promise.all([ + publicClient.readContract({ + address: GD_TOKEN, abi: (await import('./constants')).ERC20_ABI, + functionName: 'balanceOf', args: [userAddress], + }), + publicClient.readContract({ + address: USDGLO_TOKEN, abi: (await import('./constants')).ERC20_ABI, + functionName: 'balanceOf', args: [userAddress], + }), + publicClient.readContract({ + address: GD_TOKEN, abi: (await import('./constants')).ERC20_ABI, + functionName: 'allowance', args: [userAddress, POSITION_MANAGER], + }), + publicClient.readContract({ + address: USDGLO_TOKEN, abi: (await import('./constants')).ERC20_ABI, + functionName: 'allowance', args: [userAddress, POSITION_MANAGER], + }), + ]); + + return { gdBalance, usdgloBalance, gdAllowance, usdgloAllowance }; +} + +export async function getUserPositions( + publicClient: PublicClient, + userAddress: `0x${string}`, + currentTick: number, +): Promise { + let positionCount: bigint; + try { + positionCount = await publicClient.readContract({ + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'balanceOf', + args: [userAddress], + }) as bigint; + } catch { + return []; + } + + if (positionCount === 0n) return []; + + const tokenIds: bigint[] = []; + for (let i = 0n; i < positionCount; i++) { + const tokenId = await publicClient.readContract({ + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'tokenOfOwnerByIndex', + args: [userAddress, i], + }) as bigint; + tokenIds.push(tokenId); + } + + const positions: PositionData[] = []; + for (const tokenId of tokenIds) { + const pos = await publicClient.readContract({ + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'positions', + args: [tokenId], + }) as readonly [bigint, string, string, string, number, number, number, bigint, bigint, bigint, bigint, bigint]; + + const [, , token0, token1, fee, tickLower, tickUpper, liquidity, , , tokensOwed0, tokensOwed1] = pos; + + const matchesPool = + token0.toLowerCase() === TOKEN0.toLowerCase() && + token1.toLowerCase() === TOKEN1.toLowerCase() && + fee === POOL_FEE; + + if (!matchesPool) continue; + if (liquidity === 0n && tokensOwed0 === 0n && tokensOwed1 === 0n) continue; + + const { amount0, amount1 } = calculatePositionAmounts( + liquidity, tickLower, tickUpper, currentTick, + ); + + positions.push({ + tokenId, + token0, token1, + fee, tickLower, tickUpper, + liquidity, + tokensOwed0, tokensOwed1, + amount0, amount1, + inRange: currentTick >= tickLower && currentTick < tickUpper, + }); + } + + return positions; +} + +function calculatePositionAmounts( + liquidity: bigint, + tickLower: number, + tickUpper: number, + currentTick: number, +): { amount0: bigint; amount1: bigint } { + if (liquidity === 0n) return { amount0: 0n, amount1: 0n }; + + const sqrtPriceLower = tickToSqrtPrice(tickLower); + const sqrtPriceUpper = tickToSqrtPrice(tickUpper); + const sqrtPriceCurrent = tickToSqrtPrice(currentTick); + + const L = Number(liquidity); + let amount0 = 0; + let amount1 = 0; + + if (currentTick < tickLower) { + amount0 = L * (sqrtPriceUpper - sqrtPriceLower) / (sqrtPriceLower * sqrtPriceUpper); + } else if (currentTick >= tickUpper) { + amount1 = L * (sqrtPriceUpper - sqrtPriceLower); + } else { + amount0 = L * (sqrtPriceUpper - sqrtPriceCurrent) / (sqrtPriceCurrent * sqrtPriceUpper); + amount1 = L * (sqrtPriceCurrent - sqrtPriceLower); + } + + return { + amount0: BigInt(Math.floor(amount0)), + amount1: BigInt(Math.floor(amount1)), + }; +} + +export function formatBigIntDisplay(num: bigint): string { + return Intl.NumberFormat().format(Number(formatEther(num))); +} + +export function formatAmount(num: number): string { + if (num === 0) return '0'; + return num.toFixed(6).replace(/\.?0+$/, ''); +} + +export function getGdAndUsdgloAmounts( + amount0: bigint, + amount1: bigint, +): { gdAmount: bigint; usdgloAmount: bigint } { + return { + gdAmount: IS_GD_TOKEN0 ? amount0 : amount1, + usdgloAmount: IS_GD_TOKEN0 ? amount1 : amount0, + }; +} diff --git a/packages/liquidity-widget/src/liquidity/tx-service.ts b/packages/liquidity-widget/src/liquidity/tx-service.ts new file mode 100644 index 0000000..9bf7df2 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/tx-service.ts @@ -0,0 +1,166 @@ +import type { PublicClient, WalletClient } from 'viem'; +import { + POSITION_MANAGER, POSITION_MANAGER_ABI, ERC20_ABI, + TOKEN0, TOKEN1, POOL_FEE, IS_GD_TOKEN0, +} from './constants'; + +const MAX_UINT128 = 2n ** 128n - 1n; + +export interface TxCallbacks { + onHash?: (hash: `0x${string}`) => void; + onConfirmed?: (hash: `0x${string}`) => void; +} + +export async function approveToken( + publicClient: PublicClient, + walletClient: WalletClient, + account: `0x${string}`, + tokenAddress: `0x${string}`, + amount: bigint, + bufferPercent: number = 5, + callbacks?: TxCallbacks, +): Promise<`0x${string}`> { + const bufferedAmount = amount + (amount * BigInt(bufferPercent) / 100n); + + const { request } = await publicClient.simulateContract({ + account, + address: tokenAddress, + abi: ERC20_ABI, + functionName: 'approve', + args: [POSITION_MANAGER, bufferedAmount], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + + await publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; +} + +export async function addLiquidity( + publicClient: PublicClient, + walletClient: WalletClient, + account: `0x${string}`, + gdAmountWei: bigint, + usdgloAmountWei: bigint, + tickLower: number, + tickUpper: number, + callbacks?: TxCallbacks, +): Promise<`0x${string}`> { + const amount0Desired = IS_GD_TOKEN0 ? gdAmountWei : usdgloAmountWei; + const amount1Desired = IS_GD_TOKEN0 ? usdgloAmountWei : gdAmountWei; + const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); + + const { request } = await publicClient.simulateContract({ + account, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'mint', + args: [{ + token0: TOKEN0, + token1: TOKEN1, + fee: POOL_FEE, + tickLower, + tickUpper, + amount0Desired, + amount1Desired, + amount0Min: 0n, + amount1Min: 0n, + recipient: account, + deadline, + }], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + + await publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; +} + +export async function removeLiquidity( + publicClient: PublicClient, + walletClient: WalletClient, + account: `0x${string}`, + tokenId: bigint, + liquidity: bigint, + callbacks?: TxCallbacks, +): Promise<`0x${string}`> { + const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); + + const { request: decreaseReq } = await publicClient.simulateContract({ + account, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'decreaseLiquidity', + args: [{ + tokenId, + liquidity: BigInt(liquidity) as unknown as bigint & { __brand: 'uint128' }, + amount0Min: 0n, + amount1Min: 0n, + deadline, + }], + }); + + const hash = await walletClient.writeContract(decreaseReq); + callbacks?.onHash?.(hash); + await publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; +} + +export async function collectFees( + publicClient: PublicClient, + walletClient: WalletClient, + account: `0x${string}`, + tokenId: bigint, + callbacks?: TxCallbacks, +): Promise<`0x${string}`> { + const { request } = await publicClient.simulateContract({ + account, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'collect', + args: [{ + tokenId, + recipient: account, + amount0Max: MAX_UINT128, + amount1Max: MAX_UINT128, + }], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + + await publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; +} + +export function parseTxError(error: any): string { + const msg = error?.message || error?.toString() || ''; + + if (msg.includes('User rejected') || msg.includes('user rejected') || msg.includes('ACTION_REJECTED')) + return 'Transaction was rejected in your wallet.'; + if (msg.includes('insufficient funds') || msg.includes('InsufficientFunds')) + return 'Insufficient funds to cover gas fees.'; + if (msg.includes('exceeds balance')) + return 'Token balance too low for this transaction.'; + if (msg.includes('UNPREDICTABLE_GAS') || msg.includes('execution reverted')) + return 'Transaction would fail on-chain. Try adjusting your amounts.'; + if (msg.includes('nonce')) + return 'Transaction nonce conflict. Please reset your wallet or wait for pending transactions.'; + + if (msg.length > 120) return 'Transaction failed. Please try again.'; + return msg || 'Transaction failed. Please try again.'; +} diff --git a/packages/liquidity-widget/src/liquidity/types.ts b/packages/liquidity-widget/src/liquidity/types.ts new file mode 100644 index 0000000..4d14de7 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/types.ts @@ -0,0 +1,52 @@ +export type StepStatus = 'pending' | 'active' | 'completed' | 'skipped'; + +export interface TxStepInfo { + label: string; + status: StepStatus; + txHash?: string; +} + +export type TxFlowPhase = + | 'idle' + | 'approving-gd' + | 'approving-usdglo' + | 'minting' + | 'success' + | 'error'; + +export interface RangePreset { + id: 'full' | 'wide' | 'narrow'; + label: string; + description: string; + tooltip: string; + getTickRange: (currentTick: number, tickSpacing: number) => { tickLower: number; tickUpper: number }; + concentrationMultiplier: number; +} + +export interface PositionData { + tokenId: bigint; + token0: string; + token1: string; + fee: number; + tickLower: number; + tickUpper: number; + liquidity: bigint; + tokensOwed0: bigint; + tokensOwed1: bigint; + amount0: bigint; + amount1: bigint; + inRange: boolean; +} + +export interface WidgetTheme { + primaryColor: string; + borderRadius: string; + fontFamily: string; +} + +export interface PoolData { + sqrtPriceX96: bigint; + currentTick: number; + price: number; + gdPriceInUsdglo: number; +} diff --git a/packages/liquidity-widget/tsconfig.json b/packages/liquidity-widget/tsconfig.json new file mode 100644 index 0000000..e9d7076 --- /dev/null +++ b/packages/liquidity-widget/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "target": "ES2022", + "experimentalDecorators": true, + "useDefineForClassFields": false + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/liquidity-widget/tsup.config.liquidity.ts b/packages/liquidity-widget/tsup.config.liquidity.ts new file mode 100644 index 0000000..b2e51b3 --- /dev/null +++ b/packages/liquidity-widget/tsup.config.liquidity.ts @@ -0,0 +1,15 @@ +import { defineConfig } from "tsup" + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "iife"], + platform: "browser", + globalName: "GooddollarLiquidityWidget", + splitting: false, + sourcemap: false, + clean: true, + dts: false, + minify: true, + target: "ESNext", + outDir: "dist", +}) From cb71d807189717983aea3fb14274f280ab04b4cb Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Thu, 9 Apr 2026 19:50:13 +0300 Subject: [PATCH 02/11] fix: changes that fixes issues in code review --- .../src/GooddollarLiquidityWidget.ts | 161 +++++++++++------- .../src/liquidity/constants.ts | 123 +------------ .../src/liquidity/pool-service.ts | 83 +++++---- .../src/liquidity/tx-service.ts | 8 +- .../src/liquidity/validation.ts | 36 ++++ .../liquidity-widget/tsup.config.liquidity.ts | 2 +- 6 files changed, 201 insertions(+), 212 deletions(-) create mode 100644 packages/liquidity-widget/src/liquidity/validation.ts diff --git a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts index 3698897..762fe6d 100644 --- a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts +++ b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts @@ -1,6 +1,6 @@ import { LitElement, html, css, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { createWalletClient, createPublicClient, custom, http, formatEther, parseEther } from 'viem'; +import { createWalletClient, createPublicClient, custom, http, formatEther } from 'viem'; import type { PublicClient, WalletClient } from 'viem'; import { celo } from 'viem/chains'; @@ -13,6 +13,7 @@ import { import type { TxFlowPhase, TxStepInfo, PositionData, WidgetTheme } from './liquidity/types'; import { loadPoolData, loadUserBalancesAndAllowances, getUserPositions, formatBigIntDisplay, formatAmount } from './liquidity/pool-service'; import { approveToken, addLiquidity, parseTxError } from './liquidity/tx-service'; +import { safeParseEther, validateInputs } from './liquidity/validation'; import { RANGE_PRESETS } from './liquidity/components/lw-range-presets'; import './liquidity/components/lw-stepper'; @@ -25,6 +26,16 @@ import './liquidity/components/lw-positions-panel'; type WidgetTab = 'add' | 'positions'; +export function updateStep( + steps: TxStepInfo[], + index: number, + patch: Partial, +): TxStepInfo[] { + const next = steps.slice(); + next[index] = { ...next[index], ...patch }; + return next; +} + @customElement('gooddollar-liquidity-widget') export class GooddollarLiquidityWidget extends LitElement { @@ -51,6 +62,9 @@ export class GooddollarLiquidityWidget extends LitElement { @property({ type: Object }) theme: Partial | undefined = undefined; + @property({ type: Number }) + refreshInterval: number = 30_000; + // ── Internal State ───────────────────────────────────────────────── @state() private activeTab: WidgetTab = 'add'; @@ -80,7 +94,36 @@ export class GooddollarLiquidityWidget extends LitElement { private walletClient: WalletClient | null = null; private publicClient: PublicClient | null = null; private userAddress: string | null = null; - private refreshInterval: ReturnType | null = null; + private _refreshTimer: ReturnType | null = null; + + // ── Bigint helpers (avoid precision loss) ────────────────────────── + + private static readonly Q96 = 2n ** 96n; + private static readonly Q192 = 2n ** 192n; + + private static _pow10(decimals: number): bigint { + // decimals is small/constant in this widget; simple loop is fine. + let x = 1n; + for (let i = 0; i < decimals; i++) x *= 10n; + return x; + } + + private static _formatFixed(value: bigint, decimals: number): string { + // Returns a base-10 string with `decimals` fractional digits. + const negative = value < 0n; + const v = negative ? -value : value; + const base = GooddollarLiquidityWidget._pow10(decimals); + const whole = v / base; + const frac = v % base; + const fracStr = frac.toString().padStart(decimals, '0'); + return `${negative ? '-' : ''}${whole.toString()}${decimals > 0 ? `.${fracStr}` : ''}`; + } + + private static _toFiniteNumber(value: string): number { + // Convert a decimal string to number, but never return NaN/Infinity. + const n = Number(value); + return Number.isFinite(n) ? n : 0; + } // ── Styles ───────────────────────────────────────────────────────── @@ -196,20 +239,38 @@ export class GooddollarLiquidityWidget extends LitElement { connectedCallback(): void { super.connectedCallback(); this.selectedRange = this.defaultRange; - this.refreshInterval = setInterval(() => this.refreshData(), 30_000); this.refreshData(); } disconnectedCallback() { super.disconnectedCallback(); - if (this.refreshInterval) clearInterval(this.refreshInterval); + this._stopRefreshTimer(); } updated(changed: Map) { if (changed.has('web3Provider')) this.refreshData(); + if (changed.has('refreshInterval')) this._syncRefreshTimer(); if (changed.has('theme')) this._applyTheme(); } + private get _isConnected(): boolean { + return !!(this.web3Provider && this.web3Provider.isConnected && this.userAddress); + } + + private _syncRefreshTimer() { + this._stopRefreshTimer(); + if (this._isConnected && this.refreshInterval > 0) { + this._refreshTimer = setInterval(() => this.refreshData(), this.refreshInterval); + } + } + + private _stopRefreshTimer() { + if (this._refreshTimer) { + clearInterval(this._refreshTimer); + this._refreshTimer = null; + } + } + // ── Render ───────────────────────────────────────────────────────── render() { @@ -400,6 +461,7 @@ export class GooddollarLiquidityWidget extends LitElement { } this.isLoading = false; + this._syncRefreshTimer(); } private _resetUserData() { @@ -430,13 +492,22 @@ export class GooddollarLiquidityWidget extends LitElement { private _getGdPriceInUsdglo(): number { if (this.sqrtPriceX96 === 0n) return 0; - const sqrtPrice = Number(this.sqrtPriceX96) / (2 ** 96); - const rawPrice = sqrtPrice * sqrtPrice; - return IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice; + // price = (sqrtPriceX96^2) / 2^192 + // Compute as fixed-point bigint to avoid Number overflow/precision loss. + const scale = 18; + const scaledPrice = (this.sqrtPriceX96 * this.sqrtPriceX96 * GooddollarLiquidityWidget._pow10(scale)) / GooddollarLiquidityWidget.Q192; + const rawPrice = GooddollarLiquidityWidget._toFiniteNumber(GooddollarLiquidityWidget._formatFixed(scaledPrice, scale)); + if (rawPrice <= 0) return 0; + return IS_GD_TOKEN0 ? rawPrice : (1 / rawPrice); } private _getSqrtPriceFloat(): number { - return Number(this.sqrtPriceX96) / (2 ** 96); + if (this.sqrtPriceX96 === 0n) return 0; + // sqrtPrice = sqrtPriceX96 / 2^96 + // Keep this as a bounded float for UI math (range presets / input pairing). + const scale = 12; + const scaledSqrt = (this.sqrtPriceX96 * GooddollarLiquidityWidget._pow10(scale)) / GooddollarLiquidityWidget.Q96; + return GooddollarLiquidityWidget._toFiniteNumber(GooddollarLiquidityWidget._formatFixed(scaledSqrt, scale)); } private _calcAmount1From0(amount0: number): number { @@ -471,43 +542,23 @@ export class GooddollarLiquidityWidget extends LitElement { if (isFinite(gd) && gd >= 0) this.gdInput = formatAmount(gd); } - private _safeParseEther(value: string): bigint { - try { - if (!value || value.trim() === '' || value === '.') return 0n; - return parseEther(value); - } catch { return 0n; } - } - // ── Validation ───────────────────────────────────────────────────── private _validateInputs(force = false) { - this.inputError = ''; - const re = /^[0-9]*\.?[0-9]*$/; - if (this.gdInput && !re.test(this.gdInput)) { this.inputError = 'Invalid G$ value'; return; } - if (this.usdgloInput && !re.test(this.usdgloInput)) { this.inputError = 'Invalid USDGLO value'; return; } - - const gdNum = parseFloat(this.gdInput || '0'); - const usdgloNum = parseFloat(this.usdgloInput || '0'); - - if (force && (isNaN(gdNum) || gdNum <= 0 || isNaN(usdgloNum) || usdgloNum <= 0)) { - this.inputError = 'Please enter valid amounts'; - return; - } - if (gdNum > 0 && this._safeParseEther(this.gdInput) > this.gdBalance) { - this.inputError = 'Insufficient G$ balance'; - return; - } - if (usdgloNum > 0 && this._safeParseEther(this.usdgloInput) > this.usdgloBalance) { - this.inputError = 'Insufficient USDGLO balance'; - return; - } + this.inputError = validateInputs({ + gdInput: this.gdInput, + usdgloInput: this.usdgloInput, + gdBalance: this.gdBalance, + usdgloBalance: this.usdgloBalance, + force, + }) ?? ''; } private _getButtonLabel(): string { if (this.txPhase === 'success') return 'Add More Liquidity'; - const gdWei = this._safeParseEther(this.gdInput); - const usdgloWei = this._safeParseEther(this.usdgloInput); + const gdWei = safeParseEther(this.gdInput); + const usdgloWei = safeParseEther(this.usdgloInput); if (gdWei > 0n && this.gdAllowance < gdWei) return 'Approve & Add Liquidity'; if (usdgloWei > 0n && this.usdgloAllowance < usdgloWei) return 'Approve & Add Liquidity'; @@ -531,13 +582,13 @@ export class GooddollarLiquidityWidget extends LitElement { } private _handleGdMax() { - this.gdInput = Number(formatEther(this.gdBalance)).toString(); + this.gdInput = formatEther(this.gdBalance); this._calcUsdgloFromGd(); this.inputError = ''; } private _handleUsdgloMax() { - this.usdgloInput = Number(formatEther(this.usdgloBalance)).toString(); + this.usdgloInput = formatEther(this.usdgloBalance); this._calcGdFromUsdglo(); this.inputError = ''; } @@ -575,27 +626,25 @@ export class GooddollarLiquidityWidget extends LitElement { if (this.inputError) return; const account = this.userAddress as `0x${string}`; - const gdWei = this._safeParseEther(this.gdInput); - const usdgloWei = this._safeParseEther(this.usdgloInput); + const gdWei = safeParseEther(this.gdInput); + const usdgloWei = safeParseEther(this.usdgloInput); const needGdApproval = gdWei > 0n && this.gdAllowance < gdWei; const needUsdgloApproval = usdgloWei > 0n && this.usdgloAllowance < usdgloWei; - const steps: TxStepInfo[] = [ + let steps: TxStepInfo[] = [ { label: 'Approve G$', status: needGdApproval ? 'pending' : 'skipped' }, { label: 'Approve USDGLO', status: needUsdgloApproval ? 'pending' : 'skipped' }, { label: 'Add Liquidity', status: 'pending' }, ]; - this.txSteps = [...steps]; + this.txSteps = steps; this.txError = ''; try { - // Step 1: Approve G$ if (needGdApproval) { - steps[0].status = 'active'; - this.txSteps = [...steps]; this.txPhase = 'approving-gd'; this.txHash = ''; + this.txSteps = updateStep(steps, 0, { status: 'active' }); const hash = await approveToken( this.publicClient, this.walletClient, account, @@ -606,18 +655,14 @@ export class GooddollarLiquidityWidget extends LitElement { }, ); - steps[0].status = 'completed'; - steps[0].txHash = hash; - this.txSteps = [...steps]; + this.txSteps = steps = updateStep(steps, 0, { status: 'completed', txHash: hash }); await this.refreshData(); } - // Step 2: Approve USDGLO if (needUsdgloApproval) { - steps[1].status = 'active'; - this.txSteps = [...steps]; this.txPhase = 'approving-usdglo'; this.txHash = ''; + this.txSteps = updateStep(steps, 1, { status: 'active' }); const hash = await approveToken( this.publicClient, this.walletClient, account, @@ -628,17 +673,13 @@ export class GooddollarLiquidityWidget extends LitElement { }, ); - steps[1].status = 'completed'; - steps[1].txHash = hash; - this.txSteps = [...steps]; + this.txSteps = steps = updateStep(steps, 1, { status: 'completed', txHash: hash }); await this.refreshData(); } - // Step 3: Mint - steps[2].status = 'active'; - this.txSteps = [...steps]; this.txPhase = 'minting'; this.txHash = ''; + this.txSteps = updateStep(steps, 2, { status: 'active' }); const hash = await addLiquidity( this.publicClient, this.walletClient, account, @@ -649,9 +690,7 @@ export class GooddollarLiquidityWidget extends LitElement { }, ); - steps[2].status = 'completed'; - steps[2].txHash = hash; - this.txSteps = [...steps]; + this.txSteps = updateStep(steps, 2, { status: 'completed', txHash: hash }); this.txPhase = 'success'; this.txHash = hash; diff --git a/packages/liquidity-widget/src/liquidity/constants.ts b/packages/liquidity-widget/src/liquidity/constants.ts index 1a9f991..4768690 100644 --- a/packages/liquidity-widget/src/liquidity/constants.ts +++ b/packages/liquidity-widget/src/liquidity/constants.ts @@ -26,121 +26,14 @@ export const POOL_ABI = parseAbi([ 'function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)', ]); -export const POSITION_MANAGER_ABI = [ - { - inputs: [ - { - components: [ - { internalType: 'address', name: 'token0', type: 'address' }, - { internalType: 'address', name: 'token1', type: 'address' }, - { internalType: 'uint24', name: 'fee', type: 'uint24' }, - { internalType: 'int24', name: 'tickLower', type: 'int24' }, - { internalType: 'int24', name: 'tickUpper', type: 'int24' }, - { internalType: 'uint256', name: 'amount0Desired', type: 'uint256' }, - { internalType: 'uint256', name: 'amount1Desired', type: 'uint256' }, - { internalType: 'uint256', name: 'amount0Min', type: 'uint256' }, - { internalType: 'uint256', name: 'amount1Min', type: 'uint256' }, - { internalType: 'address', name: 'recipient', type: 'address' }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - ], - internalType: 'struct INonfungiblePositionManager.MintParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'mint', - outputs: [ - { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, - { internalType: 'uint128', name: 'liquidity', type: 'uint128' }, - { internalType: 'uint256', name: 'amount0', type: 'uint256' }, - { internalType: 'uint256', name: 'amount1', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'owner', type: 'address' }], - name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'uint256', name: 'index', type: 'uint256' }, - ], - name: 'tokenOfOwnerByIndex', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], - name: 'positions', - outputs: [ - { internalType: 'uint96', name: 'nonce', type: 'uint96' }, - { internalType: 'address', name: 'operator', type: 'address' }, - { internalType: 'address', name: 'token0', type: 'address' }, - { internalType: 'address', name: 'token1', type: 'address' }, - { internalType: 'uint24', name: 'fee', type: 'uint24' }, - { internalType: 'int24', name: 'tickLower', type: 'int24' }, - { internalType: 'int24', name: 'tickUpper', type: 'int24' }, - { internalType: 'uint128', name: 'liquidity', type: 'uint128' }, - { internalType: 'uint256', name: 'feeGrowthInside0LastX128', type: 'uint256' }, - { internalType: 'uint256', name: 'feeGrowthInside1LastX128', type: 'uint256' }, - { internalType: 'uint128', name: 'tokensOwed0', type: 'uint128' }, - { internalType: 'uint128', name: 'tokensOwed1', type: 'uint128' }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - components: [ - { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, - { internalType: 'uint128', name: 'liquidity', type: 'uint128' }, - { internalType: 'uint256', name: 'amount0Min', type: 'uint256' }, - { internalType: 'uint256', name: 'amount1Min', type: 'uint256' }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - ], - internalType: 'struct INonfungiblePositionManager.DecreaseLiquidityParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'decreaseLiquidity', - outputs: [ - { internalType: 'uint256', name: 'amount0', type: 'uint256' }, - { internalType: 'uint256', name: 'amount1', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, - { internalType: 'address', name: 'recipient', type: 'address' }, - { internalType: 'uint128', name: 'amount0Max', type: 'uint128' }, - { internalType: 'uint128', name: 'amount1Max', type: 'uint128' }, - ], - internalType: 'struct INonfungiblePositionManager.CollectParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'collect', - outputs: [ - { internalType: 'uint256', name: 'amount0', type: 'uint256' }, - { internalType: 'uint256', name: 'amount1', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, -] as const; +export const POSITION_MANAGER_ABI = parseAbi([ + 'function mint((address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint256 amount0Desired, uint256 amount1Desired, uint256 amount0Min, uint256 amount1Min, address recipient, uint256 deadline) params) payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)', + 'function balanceOf(address owner) view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)', + 'function positions(uint256 tokenId) view returns (uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1)', + 'function decreaseLiquidity((uint256 tokenId, uint128 liquidity, uint256 amount0Min, uint256 amount1Min, uint256 deadline) params) payable returns (uint256 amount0, uint256 amount1)', + 'function collect((uint256 tokenId, address recipient, uint128 amount0Max, uint128 amount1Max) params) payable returns (uint256 amount0, uint256 amount1)', +]); export function tickToSqrtPrice(tick: number): number { return Math.sqrt(1.0001 ** tick); diff --git a/packages/liquidity-widget/src/liquidity/pool-service.ts b/packages/liquidity-widget/src/liquidity/pool-service.ts index 5eecb10..930d93a 100644 --- a/packages/liquidity-widget/src/liquidity/pool-service.ts +++ b/packages/liquidity-widget/src/liquidity/pool-service.ts @@ -3,7 +3,7 @@ import { formatEther } from 'viem'; import { POOL_ADDRESS, POOL_ABI, POSITION_MANAGER, POSITION_MANAGER_ABI, GD_TOKEN, USDGLO_TOKEN, POOL_FEE, IS_GD_TOKEN0, TOKEN0, TOKEN1, - tickToSqrtPrice, + tickToSqrtPrice, ERC20_ABI } from './constants'; import type { PoolData, PositionData } from './types'; @@ -27,24 +27,31 @@ export async function loadUserBalancesAndAllowances( publicClient: PublicClient, userAddress: `0x${string}`, ) { - const [gdBalance, usdgloBalance, gdAllowance, usdgloAllowance] = await Promise.all([ - publicClient.readContract({ - address: GD_TOKEN, abi: (await import('./constants')).ERC20_ABI, - functionName: 'balanceOf', args: [userAddress], - }), - publicClient.readContract({ - address: USDGLO_TOKEN, abi: (await import('./constants')).ERC20_ABI, - functionName: 'balanceOf', args: [userAddress], - }), - publicClient.readContract({ - address: GD_TOKEN, abi: (await import('./constants')).ERC20_ABI, - functionName: 'allowance', args: [userAddress, POSITION_MANAGER], - }), - publicClient.readContract({ - address: USDGLO_TOKEN, abi: (await import('./constants')).ERC20_ABI, - functionName: 'allowance', args: [userAddress, POSITION_MANAGER], - }), - ]); + const results = await publicClient.multicall({ + contracts: [ + { + address: GD_TOKEN, abi: ERC20_ABI, + functionName: 'balanceOf' as const, args: [userAddress], + }, + { + address: USDGLO_TOKEN, abi: ERC20_ABI, + functionName: 'balanceOf' as const, args: [userAddress], + }, + { + address: GD_TOKEN, abi: ERC20_ABI, + functionName: 'allowance' as const, args: [userAddress, POSITION_MANAGER], + }, + { + address: USDGLO_TOKEN, abi: ERC20_ABI, + functionName: 'allowance' as const, args: [userAddress, POSITION_MANAGER], + }, + ], + }); + + const gdBalance = results[0].status === 'success' ? results[0].result as bigint : 0n; + const usdgloBalance = results[1].status === 'success' ? results[1].result as bigint : 0n; + const gdAllowance = results[2].status === 'success' ? results[2].result as bigint : 0n; + const usdgloAllowance = results[3].status === 'success' ? results[3].result as bigint : 0n; return { gdBalance, usdgloBalance, gdAllowance, usdgloAllowance }; } @@ -68,26 +75,36 @@ export async function getUserPositions( if (positionCount === 0n) return []; - const tokenIds: bigint[] = []; - for (let i = 0n; i < positionCount; i++) { - const tokenId = await publicClient.readContract({ + const tokenIdResults = await publicClient.multicall({ + contracts: Array.from({ length: Number(positionCount) }, (_, i) => ({ address: POSITION_MANAGER, abi: POSITION_MANAGER_ABI, - functionName: 'tokenOfOwnerByIndex', - args: [userAddress, i], - }) as bigint; - tokenIds.push(tokenId); - } + functionName: 'tokenOfOwnerByIndex' as const, + args: [userAddress, BigInt(i)], + })), + }); - const positions: PositionData[] = []; - for (const tokenId of tokenIds) { - const pos = await publicClient.readContract({ + const tokenIds = tokenIdResults + .filter((r) => r.status === 'success') + .map((r) => r.result as bigint); + + if (tokenIds.length === 0) return []; + + const positionResults = await publicClient.multicall({ + contracts: tokenIds.map((tokenId) => ({ address: POSITION_MANAGER, abi: POSITION_MANAGER_ABI, - functionName: 'positions', + functionName: 'positions' as const, args: [tokenId], - }) as readonly [bigint, string, string, string, number, number, number, bigint, bigint, bigint, bigint, bigint]; + })), + }); + + const positions: PositionData[] = []; + for (let i = 0; i < tokenIds.length; i++) { + const res = positionResults[i]; + if (res.status !== 'success') continue; + const pos = res.result as readonly [bigint, string, string, string, number, number, number, bigint, bigint, bigint, bigint, bigint]; const [, , token0, token1, fee, tickLower, tickUpper, liquidity, , , tokensOwed0, tokensOwed1] = pos; const matchesPool = @@ -103,7 +120,7 @@ export async function getUserPositions( ); positions.push({ - tokenId, + tokenId: tokenIds[i], token0, token1, fee, tickLower, tickUpper, liquidity, diff --git a/packages/liquidity-widget/src/liquidity/tx-service.ts b/packages/liquidity-widget/src/liquidity/tx-service.ts index 9bf7df2..a6ad8b4 100644 --- a/packages/liquidity-widget/src/liquidity/tx-service.ts +++ b/packages/liquidity-widget/src/liquidity/tx-service.ts @@ -20,7 +20,7 @@ export async function approveToken( bufferPercent: number = 5, callbacks?: TxCallbacks, ): Promise<`0x${string}`> { - const bufferedAmount = amount + (amount * BigInt(bufferPercent) / 100n); + const bufferedAmount = amount + (amount * BigInt(Math.round(bufferPercent * 100)) / 10000n); const { request } = await publicClient.simulateContract({ account, @@ -92,6 +92,10 @@ export async function removeLiquidity( liquidity: bigint, callbacks?: TxCallbacks, ): Promise<`0x${string}`> { + if (liquidity > MAX_UINT128) { + throw new Error('Liquidity value exceeds uint128 maximum'); + } + const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); const { request: decreaseReq } = await publicClient.simulateContract({ @@ -101,7 +105,7 @@ export async function removeLiquidity( functionName: 'decreaseLiquidity', args: [{ tokenId, - liquidity: BigInt(liquidity) as unknown as bigint & { __brand: 'uint128' }, + liquidity: liquidity as unknown as bigint & { __brand: 'uint128' }, amount0Min: 0n, amount1Min: 0n, deadline, diff --git a/packages/liquidity-widget/src/liquidity/validation.ts b/packages/liquidity-widget/src/liquidity/validation.ts new file mode 100644 index 0000000..81119f5 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/validation.ts @@ -0,0 +1,36 @@ +import { parseEther } from 'viem'; + +export function safeParseEther(value: string): bigint { + try { + if (!value || value.trim() === '' || value === '.') return 0n; + return parseEther(value); + } catch { + return 0n; + } +} + +const INPUT_RE = /^[0-9]*\.?[0-9]*$/; + +export function validateInputs(params: { + gdInput: string; + usdgloInput: string; + gdBalance: bigint; + usdgloBalance: bigint; + force?: boolean; +}): string | null { + const { gdInput, usdgloInput, gdBalance, usdgloBalance, force } = params; + + if (gdInput && !INPUT_RE.test(gdInput)) return 'Invalid G$ value'; + if (usdgloInput && !INPUT_RE.test(usdgloInput)) return 'Invalid USDGLO value'; + + const gdNum = parseFloat(gdInput || '0'); + const usdgloNum = parseFloat(usdgloInput || '0'); + + if (force && (isNaN(gdNum) || gdNum <= 0 || isNaN(usdgloNum) || usdgloNum <= 0)) { + return 'Please enter valid amounts'; + } + if (gdNum > 0 && safeParseEther(gdInput) > gdBalance) return 'Insufficient G$ balance'; + if (usdgloNum > 0 && safeParseEther(usdgloInput) > usdgloBalance) return 'Insufficient USDGLO balance'; + + return null; +} diff --git a/packages/liquidity-widget/tsup.config.liquidity.ts b/packages/liquidity-widget/tsup.config.liquidity.ts index b2e51b3..96d1f8b 100644 --- a/packages/liquidity-widget/tsup.config.liquidity.ts +++ b/packages/liquidity-widget/tsup.config.liquidity.ts @@ -8,7 +8,7 @@ export default defineConfig({ splitting: false, sourcemap: false, clean: true, - dts: false, + dts: true, minify: true, target: "ESNext", outDir: "dist", From faaeb5bb0b5a795b47d04011a52ae0c2c6851cfd Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Fri, 10 Apr 2026 16:37:19 +0300 Subject: [PATCH 03/11] fix: fix precision bugs, centralize shared math, and extract helpers --- packages/liquidity-widget/README.md | 7 +- .../src/GooddollarLiquidityWidget.ts | 80 ++++--------------- .../src/liquidity/liquidity-math.ts | 50 ++++++++++++ .../src/liquidity/pool-service.ts | 48 +++-------- .../src/liquidity/price-math.ts | 49 ++++++++++++ .../src/liquidity/tx-steps.ts | 27 +++++++ .../liquidity-widget/src/liquidity/types.ts | 2 +- yarn.lock | 12 +++ 8 files changed, 170 insertions(+), 105 deletions(-) create mode 100644 packages/liquidity-widget/src/liquidity/liquidity-math.ts create mode 100644 packages/liquidity-widget/src/liquidity/price-math.ts create mode 100644 packages/liquidity-widget/src/liquidity/tx-steps.ts diff --git a/packages/liquidity-widget/README.md b/packages/liquidity-widget/README.md index d2b6d75..3ee3753 100644 --- a/packages/liquidity-widget/README.md +++ b/packages/liquidity-widget/README.md @@ -4,7 +4,7 @@ The `gooddollar-liquidity-widget` web component provides a simple and interactiv ## Integrating The Component -Can be used in any website, for a quick setup: +This component can be used on any website. For a quick setup: 1. **Download the Script**: Download the `index.global.js` file from the project releases or build it from the source. 2. **Include in HTML**: Add the script to your HTML file. @@ -61,7 +61,7 @@ Customize the `gooddollar-liquidity-widget` using these properties: Defines the function called when the "Connect Wallet" button is clicked. - **`web3Provider`**: _(Set via JavaScript property)_ - The web3Provider object when the wallet is connected. Wallet connection logic should be handled outside of this component. + The web3Provider object to use when the wallet is connected. Wallet connection logic should be handled outside of this component. - **`explorerBaseUrl`**: _(String, default: `"https://celoscan.io"`)_ Base URL used for linking transaction hashes to a block explorer. @@ -75,6 +75,9 @@ Customize the `gooddollar-liquidity-widget` using these properties: - **`showPositions`**: _(Boolean, default: `true`)_ Whether to show the "My Positions" tab, which lists the user's existing liquidity positions. +- **`refreshInterval`**: _(Number, default: `30000`)_ + Interval in milliseconds for automatically refreshing pool data and user balances. Set to `0` to disable auto-refresh. + - **`theme`**: _(Object, optional)_ Override visual styling. Accepts an object with any of the following keys: - `primaryColor` – accent color for buttons and highlights (CSS color string). diff --git a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts index 762fe6d..b0d92ff 100644 --- a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts +++ b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts @@ -10,10 +10,11 @@ import { FULL_RANGE_TICK_LOWER, FULL_RANGE_TICK_UPPER, tickToSqrtPrice, } from './liquidity/constants'; -import type { TxFlowPhase, TxStepInfo, PositionData, WidgetTheme } from './liquidity/types'; +import type { TxFlowPhase, TxStepInfo, PositionData, PoolData, WidgetTheme } from './liquidity/types'; import { loadPoolData, loadUserBalancesAndAllowances, getUserPositions, formatBigIntDisplay, formatAmount } from './liquidity/pool-service'; import { approveToken, addLiquidity, parseTxError } from './liquidity/tx-service'; import { safeParseEther, validateInputs } from './liquidity/validation'; +import { buildTxSteps } from './liquidity/tx-steps'; import { RANGE_PRESETS } from './liquidity/components/lw-range-presets'; import './liquidity/components/lw-stepper'; @@ -74,7 +75,7 @@ export class GooddollarLiquidityWidget extends LitElement { @state() private usdgloBalance = 0n; @state() private gdAllowance = 0n; @state() private usdgloAllowance = 0n; - @state() private sqrtPriceX96 = 0n; + @state() private poolData: PoolData | null = null; @state() private currentTick = 0; @state() private isLoading = false; @state() private inputError = ''; @@ -96,35 +97,6 @@ export class GooddollarLiquidityWidget extends LitElement { private userAddress: string | null = null; private _refreshTimer: ReturnType | null = null; - // ── Bigint helpers (avoid precision loss) ────────────────────────── - - private static readonly Q96 = 2n ** 96n; - private static readonly Q192 = 2n ** 192n; - - private static _pow10(decimals: number): bigint { - // decimals is small/constant in this widget; simple loop is fine. - let x = 1n; - for (let i = 0; i < decimals; i++) x *= 10n; - return x; - } - - private static _formatFixed(value: bigint, decimals: number): string { - // Returns a base-10 string with `decimals` fractional digits. - const negative = value < 0n; - const v = negative ? -value : value; - const base = GooddollarLiquidityWidget._pow10(decimals); - const whole = v / base; - const frac = v % base; - const fracStr = frac.toString().padStart(decimals, '0'); - return `${negative ? '-' : ''}${whole.toString()}${decimals > 0 ? `.${fracStr}` : ''}`; - } - - private static _toFiniteNumber(value: string): number { - // Convert a decimal string to number, but never return NaN/Infinity. - const n = Number(value); - return Number.isFinite(n) ? n : 0; - } - // ── Styles ───────────────────────────────────────────────────────── static styles = css` @@ -275,7 +247,7 @@ export class GooddollarLiquidityWidget extends LitElement { render() { const isConnected = !!(this.web3Provider && this.web3Provider.isConnected && this.userAddress); - const gdPrice = this._getGdPriceInUsdglo(); + const gdPrice = this.poolData?.gdPriceInUsdglo ?? 0; return html`
@@ -433,7 +405,7 @@ export class GooddollarLiquidityWidget extends LitElement { try { const pool = await loadPoolData(this.publicClient); - this.sqrtPriceX96 = pool.sqrtPriceX96; + this.poolData = pool; this.currentTick = pool.currentTick; } catch (e) { console.error('Error loading pool data:', e); @@ -490,28 +462,8 @@ export class GooddollarLiquidityWidget extends LitElement { // ── Price & Amount Math ──────────────────────────────────────────── - private _getGdPriceInUsdglo(): number { - if (this.sqrtPriceX96 === 0n) return 0; - // price = (sqrtPriceX96^2) / 2^192 - // Compute as fixed-point bigint to avoid Number overflow/precision loss. - const scale = 18; - const scaledPrice = (this.sqrtPriceX96 * this.sqrtPriceX96 * GooddollarLiquidityWidget._pow10(scale)) / GooddollarLiquidityWidget.Q192; - const rawPrice = GooddollarLiquidityWidget._toFiniteNumber(GooddollarLiquidityWidget._formatFixed(scaledPrice, scale)); - if (rawPrice <= 0) return 0; - return IS_GD_TOKEN0 ? rawPrice : (1 / rawPrice); - } - - private _getSqrtPriceFloat(): number { - if (this.sqrtPriceX96 === 0n) return 0; - // sqrtPrice = sqrtPriceX96 / 2^96 - // Keep this as a bounded float for UI math (range presets / input pairing). - const scale = 12; - const scaledSqrt = (this.sqrtPriceX96 * GooddollarLiquidityWidget._pow10(scale)) / GooddollarLiquidityWidget.Q96; - return GooddollarLiquidityWidget._toFiniteNumber(GooddollarLiquidityWidget._formatFixed(scaledSqrt, scale)); - } - private _calcAmount1From0(amount0: number): number { - const sqC = this._getSqrtPriceFloat(); + const sqC = this.poolData?.sqrtPriceFloat ?? 0; const sqL = tickToSqrtPrice(this.tickLower); const sqU = tickToSqrtPrice(this.tickUpper); if (sqU <= sqL || sqC <= sqL || sqC >= sqU) return 0; @@ -520,7 +472,7 @@ export class GooddollarLiquidityWidget extends LitElement { } private _calcAmount0From1(amount1: number): number { - const sqC = this._getSqrtPriceFloat(); + const sqC = this.poolData?.sqrtPriceFloat ?? 0; const sqL = tickToSqrtPrice(this.tickLower); const sqU = tickToSqrtPrice(this.tickUpper); if (sqU <= sqL || sqC >= sqU || sqC <= sqL) return 0; @@ -530,14 +482,14 @@ export class GooddollarLiquidityWidget extends LitElement { private _calcUsdgloFromGd() { const gd = parseFloat(this.gdInput); - if (isNaN(gd) || gd <= 0 || this.sqrtPriceX96 === 0n) { this.usdgloInput = ''; return; } + if (isNaN(gd) || gd <= 0 || !this.poolData) { this.usdgloInput = ''; return; } const usdglo = IS_GD_TOKEN0 ? this._calcAmount1From0(gd) : this._calcAmount0From1(gd); if (isFinite(usdglo) && usdglo >= 0) this.usdgloInput = formatAmount(usdglo); } private _calcGdFromUsdglo() { const u = parseFloat(this.usdgloInput); - if (isNaN(u) || u <= 0 || this.sqrtPriceX96 === 0n) { this.gdInput = ''; return; } + if (isNaN(u) || u <= 0 || !this.poolData) { this.gdInput = ''; return; } const gd = IS_GD_TOKEN0 ? this._calcAmount0From1(u) : this._calcAmount1From0(u); if (isFinite(gd) && gd >= 0) this.gdInput = formatAmount(gd); } @@ -629,14 +581,14 @@ export class GooddollarLiquidityWidget extends LitElement { const gdWei = safeParseEther(this.gdInput); const usdgloWei = safeParseEther(this.usdgloInput); - const needGdApproval = gdWei > 0n && this.gdAllowance < gdWei; - const needUsdgloApproval = usdgloWei > 0n && this.usdgloAllowance < usdgloWei; + const { steps: initialSteps, needGdApproval, needUsdgloApproval } = buildTxSteps({ + gdWei, + usdgloWei, + gdAllowance: this.gdAllowance, + usdgloAllowance: this.usdgloAllowance, + }); - let steps: TxStepInfo[] = [ - { label: 'Approve G$', status: needGdApproval ? 'pending' : 'skipped' }, - { label: 'Approve USDGLO', status: needUsdgloApproval ? 'pending' : 'skipped' }, - { label: 'Add Liquidity', status: 'pending' }, - ]; + let steps: TxStepInfo[] = initialSteps; this.txSteps = steps; this.txError = ''; diff --git a/packages/liquidity-widget/src/liquidity/liquidity-math.ts b/packages/liquidity-widget/src/liquidity/liquidity-math.ts new file mode 100644 index 0000000..9f8ccb3 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/liquidity-math.ts @@ -0,0 +1,50 @@ +import { tickToSqrtPrice } from './constants'; + +/** + * Approximate token amounts held by a Uniswap V3 position. + * + * This is a UI-grade approximation: liquidity (uint128) may exceed + * `Number.MAX_SAFE_INTEGER`, so we scale it down before converting to float + * and multiply the result back up to avoid silent overflow/precision loss. + */ +export function getAmountsForPositionApprox( + liquidity: bigint, + tickLower: number, + tickUpper: number, + currentTick: number, +): { amount0: bigint; amount1: bigint } { + if (liquidity === 0n) return { amount0: 0n, amount1: 0n }; + + let scaleFactor = 1n; + let scaled = liquidity; + while (scaled > BigInt(Number.MAX_SAFE_INTEGER)) { + scaled /= 10n; + scaleFactor *= 10n; + } + const L = Number(scaled); + + const sqrtPriceLower = tickToSqrtPrice(tickLower); + const sqrtPriceUpper = tickToSqrtPrice(tickUpper); + const sqrtPriceCurrent = tickToSqrtPrice(currentTick); + + let amount0 = 0; + let amount1 = 0; + + if (currentTick < tickLower) { + amount0 = + (L * (sqrtPriceUpper - sqrtPriceLower)) / + (sqrtPriceLower * sqrtPriceUpper); + } else if (currentTick >= tickUpper) { + amount1 = L * (sqrtPriceUpper - sqrtPriceLower); + } else { + amount0 = + (L * (sqrtPriceUpper - sqrtPriceCurrent)) / + (sqrtPriceCurrent * sqrtPriceUpper); + amount1 = L * (sqrtPriceCurrent - sqrtPriceLower); + } + + return { + amount0: BigInt(Math.max(0, Math.floor(amount0))) * scaleFactor, + amount1: BigInt(Math.max(0, Math.floor(amount1))) * scaleFactor, + }; +} diff --git a/packages/liquidity-widget/src/liquidity/pool-service.ts b/packages/liquidity-widget/src/liquidity/pool-service.ts index 930d93a..303b363 100644 --- a/packages/liquidity-widget/src/liquidity/pool-service.ts +++ b/packages/liquidity-widget/src/liquidity/pool-service.ts @@ -3,8 +3,10 @@ import { formatEther } from 'viem'; import { POOL_ADDRESS, POOL_ABI, POSITION_MANAGER, POSITION_MANAGER_ABI, GD_TOKEN, USDGLO_TOKEN, POOL_FEE, IS_GD_TOKEN0, TOKEN0, TOKEN1, - tickToSqrtPrice, ERC20_ABI + ERC20_ABI } from './constants'; +import { computeGdPriceFromSqrtPrice, computeSqrtPriceFloat } from './price-math'; +import { getAmountsForPositionApprox } from './liquidity-math'; import type { PoolData, PositionData } from './types'; export async function loadPoolData(publicClient: PublicClient): Promise { @@ -16,11 +18,10 @@ export async function loadPoolData(publicClient: PublicClient): Promise= tickUpper) { - amount1 = L * (sqrtPriceUpper - sqrtPriceLower); - } else { - amount0 = L * (sqrtPriceUpper - sqrtPriceCurrent) / (sqrtPriceCurrent * sqrtPriceUpper); - amount1 = L * (sqrtPriceCurrent - sqrtPriceLower); - } - - return { - amount0: BigInt(Math.floor(amount0)), - amount1: BigInt(Math.floor(amount1)), - }; -} - export function formatBigIntDisplay(num: bigint): string { - return Intl.NumberFormat().format(Number(formatEther(num))); + const n = Number(formatEther(num)); + if (!Number.isFinite(n)) return '0'; + return Intl.NumberFormat().format(n); } export function formatAmount(num: number): string { diff --git a/packages/liquidity-widget/src/liquidity/price-math.ts b/packages/liquidity-widget/src/liquidity/price-math.ts new file mode 100644 index 0000000..668d8c1 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/price-math.ts @@ -0,0 +1,49 @@ +import { IS_GD_TOKEN0 } from './constants'; + +const Q96 = 2n ** 96n; +const Q192 = 2n ** 192n; + +function pow10(decimals: number): bigint { + let x = 1n; + for (let i = 0; i < decimals; i++) x *= 10n; + return x; +} + +function formatFixed(value: bigint, decimals: number): string { + const negative = value < 0n; + const v = negative ? -value : value; + const base = pow10(decimals); + const whole = v / base; + const frac = v % base; + const fracStr = frac.toString().padStart(decimals, '0'); + return `${negative ? '-' : ''}${whole.toString()}${decimals > 0 ? `.${fracStr}` : ''}`; +} + +function toFiniteNumber(value: string): number { + const n = Number(value); + return Number.isFinite(n) ? n : 0; +} + +/** + * Compute the G$ price in USDGLO from the on-chain sqrtPriceX96. + * Uses bigint fixed-point arithmetic to avoid Number overflow on uint160 values. + */ +export function computeGdPriceFromSqrtPrice(sqrtPriceX96: bigint): number { + if (sqrtPriceX96 === 0n) return 0; + const scale = 18; + const scaledPrice = (sqrtPriceX96 * sqrtPriceX96 * pow10(scale)) / Q192; + const rawPrice = toFiniteNumber(formatFixed(scaledPrice, scale)); + if (rawPrice <= 0) return 0; + return IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice; +} + +/** + * Compute the human-scale sqrtPrice float from sqrtPriceX96. + * Result is `sqrtPriceX96 / 2^96` computed via bigint to preserve precision. + */ +export function computeSqrtPriceFloat(sqrtPriceX96: bigint): number { + if (sqrtPriceX96 === 0n) return 0; + const scale = 12; + const scaledSqrt = (sqrtPriceX96 * pow10(scale)) / Q96; + return toFiniteNumber(formatFixed(scaledSqrt, scale)); +} diff --git a/packages/liquidity-widget/src/liquidity/tx-steps.ts b/packages/liquidity-widget/src/liquidity/tx-steps.ts new file mode 100644 index 0000000..0e7d480 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/tx-steps.ts @@ -0,0 +1,27 @@ +import type { TxStepInfo } from './types'; + +export function buildTxSteps(params: { + gdWei: bigint; + usdgloWei: bigint; + gdAllowance: bigint; + usdgloAllowance: bigint; +}): { + steps: TxStepInfo[]; + needGdApproval: boolean; + needUsdgloApproval: boolean; +} { + const { gdWei, usdgloWei, gdAllowance, usdgloAllowance } = params; + const needGdApproval = gdWei > 0n && gdAllowance < gdWei; + const needUsdgloApproval = usdgloWei > 0n && usdgloAllowance < usdgloWei; + + const steps: TxStepInfo[] = [ + { label: 'Approve G$', status: needGdApproval ? 'pending' : 'skipped' }, + { + label: 'Approve USDGLO', + status: needUsdgloApproval ? 'pending' : 'skipped', + }, + { label: 'Add Liquidity', status: 'pending' }, + ]; + + return { steps, needGdApproval, needUsdgloApproval }; +} diff --git a/packages/liquidity-widget/src/liquidity/types.ts b/packages/liquidity-widget/src/liquidity/types.ts index 4d14de7..910603b 100644 --- a/packages/liquidity-widget/src/liquidity/types.ts +++ b/packages/liquidity-widget/src/liquidity/types.ts @@ -47,6 +47,6 @@ export interface WidgetTheme { export interface PoolData { sqrtPriceX96: bigint; currentTick: number; - price: number; gdPriceInUsdglo: number; + sqrtPriceFloat: number; } diff --git a/yarn.lock b/yarn.lock index 4bbf83b..680b73d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2193,6 +2193,18 @@ __metadata: languageName: unknown linkType: soft +"@goodsdks/liquidity-widget@workspace:packages/liquidity-widget": + version: 0.0.0-use.local + resolution: "@goodsdks/liquidity-widget@workspace:packages/liquidity-widget" + dependencies: + "@repo/typescript-config": "workspace:*" + lit: "npm:^3.1.0" + tsup: "npm:^8.3.5" + typescript: "npm:latest" + viem: "npm:latest" + languageName: unknown + linkType: soft + "@goodsdks/react-hooks@npm:*, @goodsdks/react-hooks@workspace:*, @goodsdks/react-hooks@workspace:packages/react-hooks": version: 0.0.0-use.local resolution: "@goodsdks/react-hooks@workspace:packages/react-hooks" From 2455c7e9ad927b063fe9b4b7f0531441c75f8bb2 Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Tue, 14 Apr 2026 16:36:04 +0300 Subject: [PATCH 04/11] Use mostly bigint math for liquidity calculations --- .../liquidity/components/lw-position-card.ts | 10 +++-- .../src/liquidity/pool-service.ts | 8 ++-- .../src/liquidity/price-math.ts | 39 +++++-------------- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts index 111fd67..21c05e9 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts @@ -116,10 +116,12 @@ export class LwPositionCard extends LitElement { explorerUrl: string = 'https://celoscan.io'; private _fmt(val: bigint): string { - const n = Number(formatEther(val)); - if (n === 0) return '0'; - if (n < 0.0001) return '<0.0001'; - return Intl.NumberFormat(undefined, { maximumFractionDigits: 4 }).format(n); + if (val === 0n) return '0'; + const [whole, frac = ''] = formatEther(val).split('.'); + if (whole === '0' && !/[1-9]/.test(frac.slice(0, 4))) return '<0.0001'; + const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); + const trimmedFrac = frac.slice(0, 4).replace(/0+$/, ''); + return trimmedFrac ? `${grouped}.${trimmedFrac}` : grouped; } render() { diff --git a/packages/liquidity-widget/src/liquidity/pool-service.ts b/packages/liquidity-widget/src/liquidity/pool-service.ts index 303b363..b06efc4 100644 --- a/packages/liquidity-widget/src/liquidity/pool-service.ts +++ b/packages/liquidity-widget/src/liquidity/pool-service.ts @@ -135,9 +135,11 @@ export async function getUserPositions( } export function formatBigIntDisplay(num: bigint): string { - const n = Number(formatEther(num)); - if (!Number.isFinite(n)) return '0'; - return Intl.NumberFormat().format(n); + if (num === 0n) return '0'; + const [whole, frac = ''] = formatEther(num).split('.'); + const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); + const trimmedFrac = frac.slice(0, 2).replace(/0+$/, ''); + return trimmedFrac ? `${grouped}.${trimmedFrac}` : grouped; } export function formatAmount(num: number): string { diff --git a/packages/liquidity-widget/src/liquidity/price-math.ts b/packages/liquidity-widget/src/liquidity/price-math.ts index 668d8c1..36e76cb 100644 --- a/packages/liquidity-widget/src/liquidity/price-math.ts +++ b/packages/liquidity-widget/src/liquidity/price-math.ts @@ -2,48 +2,27 @@ import { IS_GD_TOKEN0 } from './constants'; const Q96 = 2n ** 96n; const Q192 = 2n ** 192n; - -function pow10(decimals: number): bigint { - let x = 1n; - for (let i = 0; i < decimals; i++) x *= 10n; - return x; -} - -function formatFixed(value: bigint, decimals: number): string { - const negative = value < 0n; - const v = negative ? -value : value; - const base = pow10(decimals); - const whole = v / base; - const frac = v % base; - const fracStr = frac.toString().padStart(decimals, '0'); - return `${negative ? '-' : ''}${whole.toString()}${decimals > 0 ? `.${fracStr}` : ''}`; -} - -function toFiniteNumber(value: string): number { - const n = Number(value); - return Number.isFinite(n) ? n : 0; -} +const SCALE = 10n ** 18n; /** * Compute the G$ price in USDGLO from the on-chain sqrtPriceX96. - * Uses bigint fixed-point arithmetic to avoid Number overflow on uint160 values. + * All intermediate math is done in bigint to avoid uint160 overflow; + * only the final scaled result is converted to a JS number. */ export function computeGdPriceFromSqrtPrice(sqrtPriceX96: bigint): number { if (sqrtPriceX96 === 0n) return 0; - const scale = 18; - const scaledPrice = (sqrtPriceX96 * sqrtPriceX96 * pow10(scale)) / Q192; - const rawPrice = toFiniteNumber(formatFixed(scaledPrice, scale)); + const scaledPrice = (sqrtPriceX96 * sqrtPriceX96 * SCALE) / Q192; + const rawPrice = Number(scaledPrice) / 1e18; if (rawPrice <= 0) return 0; return IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice; } /** - * Compute the human-scale sqrtPrice float from sqrtPriceX96. - * Result is `sqrtPriceX96 / 2^96` computed via bigint to preserve precision. + * Compute the human-scale sqrtPrice float (= sqrtPriceX96 / 2^96) in bigint, + * converting to a JS number only at the end. */ export function computeSqrtPriceFloat(sqrtPriceX96: bigint): number { if (sqrtPriceX96 === 0n) return 0; - const scale = 12; - const scaledSqrt = (sqrtPriceX96 * pow10(scale)) / Q96; - return toFiniteNumber(formatFixed(scaledSqrt, scale)); + const scaled = (sqrtPriceX96 * SCALE) / Q96; + return Number(scaled) / 1e18; } From 9864dac7922cb08f23aa8db45780de44e01cf519 Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Tue, 14 Apr 2026 17:20:43 +0300 Subject: [PATCH 05/11] feat: introduce liquidity-sdk --- packages/liquidity-sdk/package.json | 39 ++ .../src}/constants.ts | 0 packages/liquidity-sdk/src/index.ts | 11 + .../src}/liquidity-math.ts | 0 .../src}/price-math.ts | 0 packages/liquidity-sdk/src/types.ts | 33 ++ packages/liquidity-sdk/src/viem-sdk.ts | 350 ++++++++++++++++++ packages/liquidity-sdk/src/wagmi-sdk.ts | 39 ++ packages/liquidity-sdk/tsconfig.json | 10 + packages/liquidity-sdk/tsup.config.ts | 8 + packages/liquidity-widget/package.json | 1 + .../src/GooddollarLiquidityWidget.ts | 53 ++- .../src/liquidity/components/lw-pool-info.ts | 2 +- .../liquidity/components/lw-position-card.ts | 4 +- .../components/lw-positions-panel.ts | 4 +- .../liquidity/components/lw-range-presets.ts | 6 +- .../liquidity-widget/src/liquidity/format.ts | 14 + .../src/liquidity/pool-service.ts | 158 -------- .../src/liquidity/tx-service.ts | 170 --------- .../liquidity-widget/src/liquidity/types.ts | 22 -- yarn.lock | 16 + 21 files changed, 562 insertions(+), 378 deletions(-) create mode 100644 packages/liquidity-sdk/package.json rename packages/{liquidity-widget/src/liquidity => liquidity-sdk/src}/constants.ts (100%) create mode 100644 packages/liquidity-sdk/src/index.ts rename packages/{liquidity-widget/src/liquidity => liquidity-sdk/src}/liquidity-math.ts (100%) rename packages/{liquidity-widget/src/liquidity => liquidity-sdk/src}/price-math.ts (100%) create mode 100644 packages/liquidity-sdk/src/types.ts create mode 100644 packages/liquidity-sdk/src/viem-sdk.ts create mode 100644 packages/liquidity-sdk/src/wagmi-sdk.ts create mode 100644 packages/liquidity-sdk/tsconfig.json create mode 100644 packages/liquidity-sdk/tsup.config.ts create mode 100644 packages/liquidity-widget/src/liquidity/format.ts delete mode 100644 packages/liquidity-widget/src/liquidity/pool-service.ts delete mode 100644 packages/liquidity-widget/src/liquidity/tx-service.ts diff --git a/packages/liquidity-sdk/package.json b/packages/liquidity-sdk/package.json new file mode 100644 index 0000000..6b1e858 --- /dev/null +++ b/packages/liquidity-sdk/package.json @@ -0,0 +1,39 @@ +{ + "name": "@goodsdks/liquidity-sdk", + "version": "1.0.0", + "type": "module", + "scripts": { + "build": "tsup --clean", + "dev": "tsc --watch" + }, + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "import": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.cts", + "require": "./dist/index.cjs" + } + }, + "files": [ + "dist", + "src" + ], + "devDependencies": { + "@repo/typescript-config": "workspace:*", + "typescript": "latest", + "viem": "latest", + "wagmi": "latest" + }, + "peerDependencies": { + "viem": "*", + "wagmi": "*" + }, + "dependencies": { + "tsup": "^8.3.5" + } +} diff --git a/packages/liquidity-widget/src/liquidity/constants.ts b/packages/liquidity-sdk/src/constants.ts similarity index 100% rename from packages/liquidity-widget/src/liquidity/constants.ts rename to packages/liquidity-sdk/src/constants.ts diff --git a/packages/liquidity-sdk/src/index.ts b/packages/liquidity-sdk/src/index.ts new file mode 100644 index 0000000..8e05108 --- /dev/null +++ b/packages/liquidity-sdk/src/index.ts @@ -0,0 +1,11 @@ +export * from "./viem-sdk"; +export { useGooddollarLiquidity } from "./wagmi-sdk"; +export * from "./constants"; +export * from "./price-math"; +export * from "./liquidity-math"; +export type { + PoolData, + PositionData, + TxCallbacks, + UserBalancesAndAllowances, +} from "./types"; diff --git a/packages/liquidity-widget/src/liquidity/liquidity-math.ts b/packages/liquidity-sdk/src/liquidity-math.ts similarity index 100% rename from packages/liquidity-widget/src/liquidity/liquidity-math.ts rename to packages/liquidity-sdk/src/liquidity-math.ts diff --git a/packages/liquidity-widget/src/liquidity/price-math.ts b/packages/liquidity-sdk/src/price-math.ts similarity index 100% rename from packages/liquidity-widget/src/liquidity/price-math.ts rename to packages/liquidity-sdk/src/price-math.ts diff --git a/packages/liquidity-sdk/src/types.ts b/packages/liquidity-sdk/src/types.ts new file mode 100644 index 0000000..106e0d5 --- /dev/null +++ b/packages/liquidity-sdk/src/types.ts @@ -0,0 +1,33 @@ +export interface PoolData { + sqrtPriceX96: bigint; + currentTick: number; + gdPriceInUsdglo: number; + sqrtPriceFloat: number; +} + +export interface PositionData { + tokenId: bigint; + token0: string; + token1: string; + fee: number; + tickLower: number; + tickUpper: number; + liquidity: bigint; + tokensOwed0: bigint; + tokensOwed1: bigint; + amount0: bigint; + amount1: bigint; + inRange: boolean; +} + +export interface UserBalancesAndAllowances { + gdBalance: bigint; + usdgloBalance: bigint; + gdAllowance: bigint; + usdgloAllowance: bigint; +} + +export interface TxCallbacks { + onHash?: (hash: `0x${string}`) => void; + onConfirmed?: (hash: `0x${string}`) => void; +} diff --git a/packages/liquidity-sdk/src/viem-sdk.ts b/packages/liquidity-sdk/src/viem-sdk.ts new file mode 100644 index 0000000..c3f024c --- /dev/null +++ b/packages/liquidity-sdk/src/viem-sdk.ts @@ -0,0 +1,350 @@ +import type { PublicClient, WalletClient } from 'viem'; +import { + ERC20_ABI, + GD_TOKEN, + IS_GD_TOKEN0, + POOL_ABI, + POOL_ADDRESS, + POOL_FEE, + POSITION_MANAGER, + POSITION_MANAGER_ABI, + TOKEN0, + TOKEN1, + USDGLO_TOKEN, +} from './constants'; +import { computeGdPriceFromSqrtPrice, computeSqrtPriceFloat } from './price-math'; +import { getAmountsForPositionApprox } from './liquidity-math'; +import type { + PoolData, + PositionData, + TxCallbacks, + UserBalancesAndAllowances, +} from './types'; + +const MAX_UINT128 = 2n ** 128n - 1n; +const CELO_CHAIN_ID = 42220; + +export class GooddollarLiquiditySDK { + private publicClient: PublicClient; + private walletClient: WalletClient | null = null; + + constructor(publicClient: PublicClient, walletClient?: WalletClient) { + if (!publicClient) throw new Error('Public client is required'); + if (publicClient.chain?.id !== CELO_CHAIN_ID) { + throw new Error('Public client must be connected to Celo mainnet'); + } + this.publicClient = publicClient; + if (walletClient) this.setWalletClient(walletClient); + } + + setWalletClient(walletClient: WalletClient) { + if (walletClient.chain?.id !== CELO_CHAIN_ID) { + throw new Error('Wallet client must be connected to Celo mainnet'); + } + this.walletClient = walletClient; + } + + // ── Reads ──────────────────────────────────────────────────────────── + + async loadPoolData(): Promise { + const slot0 = await this.publicClient.readContract({ + address: POOL_ADDRESS, + abi: POOL_ABI, + functionName: 'slot0', + }); + + const sqrtPriceX96 = slot0[0]; + const currentTick = slot0[1]; + + return { + sqrtPriceX96, + currentTick, + gdPriceInUsdglo: computeGdPriceFromSqrtPrice(sqrtPriceX96), + sqrtPriceFloat: computeSqrtPriceFloat(sqrtPriceX96), + }; + } + + async loadUserBalancesAndAllowances( + userAddress: `0x${string}`, + ): Promise { + const results = await this.publicClient.multicall({ + contracts: [ + { + address: GD_TOKEN, + abi: ERC20_ABI, + functionName: 'balanceOf' as const, + args: [userAddress], + }, + { + address: USDGLO_TOKEN, + abi: ERC20_ABI, + functionName: 'balanceOf' as const, + args: [userAddress], + }, + { + address: GD_TOKEN, + abi: ERC20_ABI, + functionName: 'allowance' as const, + args: [userAddress, POSITION_MANAGER], + }, + { + address: USDGLO_TOKEN, + abi: ERC20_ABI, + functionName: 'allowance' as const, + args: [userAddress, POSITION_MANAGER], + }, + ], + }); + + const gdBalance = results[0].status === 'success' ? (results[0].result as bigint) : 0n; + const usdgloBalance = results[1].status === 'success' ? (results[1].result as bigint) : 0n; + const gdAllowance = results[2].status === 'success' ? (results[2].result as bigint) : 0n; + const usdgloAllowance = results[3].status === 'success' ? (results[3].result as bigint) : 0n; + + return { gdBalance, usdgloBalance, gdAllowance, usdgloAllowance }; + } + + async getUserPositions( + userAddress: `0x${string}`, + currentTick: number, + ): Promise { + let positionCount: bigint; + try { + positionCount = (await this.publicClient.readContract({ + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'balanceOf', + args: [userAddress], + })) as bigint; + } catch { + return []; + } + + if (positionCount === 0n) return []; + + const tokenIdResults = await this.publicClient.multicall({ + contracts: Array.from({ length: Number(positionCount) }, (_, i) => ({ + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'tokenOfOwnerByIndex' as const, + args: [userAddress, BigInt(i)], + })), + }); + + const tokenIds = tokenIdResults + .filter((r) => r.status === 'success') + .map((r) => r.result as bigint); + + if (tokenIds.length === 0) return []; + + const positionResults = await this.publicClient.multicall({ + contracts: tokenIds.map((tokenId) => ({ + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'positions' as const, + args: [tokenId], + })), + }); + + const positions: PositionData[] = []; + for (let i = 0; i < tokenIds.length; i++) { + const res = positionResults[i]; + if (res.status !== 'success') continue; + + const pos = res.result as readonly [ + bigint, string, string, string, number, number, number, + bigint, bigint, bigint, bigint, bigint, + ]; + const [, , token0, token1, fee, tickLower, tickUpper, liquidity, , , tokensOwed0, tokensOwed1] = pos; + + const matchesPool = + token0.toLowerCase() === TOKEN0.toLowerCase() && + token1.toLowerCase() === TOKEN1.toLowerCase() && + fee === POOL_FEE; + + if (!matchesPool) continue; + if (liquidity === 0n && tokensOwed0 === 0n && tokensOwed1 === 0n) continue; + + const { amount0, amount1 } = getAmountsForPositionApprox( + liquidity, tickLower, tickUpper, currentTick, + ); + + positions.push({ + tokenId: tokenIds[i], + token0, token1, + fee, tickLower, tickUpper, + liquidity, + tokensOwed0, tokensOwed1, + amount0, amount1, + inRange: currentTick >= tickLower && currentTick < tickUpper, + }); + } + + return positions; + } + + // ── Writes ─────────────────────────────────────────────────────────── + + async approveToken( + tokenAddress: `0x${string}`, + amount: bigint, + bufferPercent: number = 5, + callbacks?: TxCallbacks, + ): Promise<`0x${string}`> { + const { account, walletClient } = await this.requireWallet(); + + const bufferedAmount = + amount + (amount * BigInt(Math.round(bufferPercent * 100))) / 10000n; + + const { request } = await this.publicClient.simulateContract({ + account, + address: tokenAddress, + abi: ERC20_ABI, + functionName: 'approve', + args: [POSITION_MANAGER, bufferedAmount], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + + await this.publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; + } + + async addLiquidity( + gdAmountWei: bigint, + usdgloAmountWei: bigint, + tickLower: number, + tickUpper: number, + callbacks?: TxCallbacks, + ): Promise<`0x${string}`> { + const { account, walletClient } = await this.requireWallet(); + + const amount0Desired = IS_GD_TOKEN0 ? gdAmountWei : usdgloAmountWei; + const amount1Desired = IS_GD_TOKEN0 ? usdgloAmountWei : gdAmountWei; + const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); + + const { request } = await this.publicClient.simulateContract({ + account, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'mint', + args: [{ + token0: TOKEN0, + token1: TOKEN1, + fee: POOL_FEE, + tickLower, + tickUpper, + amount0Desired, + amount1Desired, + amount0Min: 0n, + amount1Min: 0n, + recipient: account, + deadline, + }], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + + await this.publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; + } + + async removeLiquidity( + tokenId: bigint, + liquidity: bigint, + callbacks?: TxCallbacks, + ): Promise<`0x${string}`> { + if (liquidity > MAX_UINT128) { + throw new Error('Liquidity value exceeds uint128 maximum'); + } + const { account, walletClient } = await this.requireWallet(); + + const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); + + const { request } = await this.publicClient.simulateContract({ + account, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'decreaseLiquidity', + args: [{ + tokenId, + liquidity: liquidity as unknown as bigint & { __brand: 'uint128' }, + amount0Min: 0n, + amount1Min: 0n, + deadline, + }], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + await this.publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; + } + + async collectFees( + tokenId: bigint, + callbacks?: TxCallbacks, + ): Promise<`0x${string}`> { + const { account, walletClient } = await this.requireWallet(); + + const { request } = await this.publicClient.simulateContract({ + account, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'collect', + args: [{ + tokenId, + recipient: account, + amount0Max: MAX_UINT128, + amount1Max: MAX_UINT128, + }], + }); + + const hash = await walletClient.writeContract(request); + callbacks?.onHash?.(hash); + + await this.publicClient.waitForTransactionReceipt({ hash }); + callbacks?.onConfirmed?.(hash); + + await new Promise((resolve) => setTimeout(resolve, 2000)); + return hash; + } + + // ── Helpers ────────────────────────────────────────────────────────── + + static parseTxError(error: any): string { + const msg = error?.message || error?.toString() || ''; + + if (msg.includes('User rejected') || msg.includes('user rejected') || msg.includes('ACTION_REJECTED')) + return 'Transaction was rejected in your wallet.'; + if (msg.includes('insufficient funds') || msg.includes('InsufficientFunds')) + return 'Insufficient funds to cover gas fees.'; + if (msg.includes('exceeds balance')) + return 'Token balance too low for this transaction.'; + if (msg.includes('UNPREDICTABLE_GAS') || msg.includes('execution reverted')) + return 'Transaction would fail on-chain. Try adjusting your amounts.'; + if (msg.includes('nonce')) + return 'Transaction nonce conflict. Please reset your wallet or wait for pending transactions.'; + + if (msg.length > 120) return 'Transaction failed. Please try again.'; + return msg || 'Transaction failed. Please try again.'; + } + + private async requireWallet(): Promise<{ account: `0x${string}`; walletClient: WalletClient }> { + if (!this.walletClient) throw new Error('Wallet client not initialized'); + const [account] = await this.walletClient.getAddresses(); + if (!account) throw new Error('No account found in wallet client'); + return { account, walletClient: this.walletClient }; + } +} diff --git a/packages/liquidity-sdk/src/wagmi-sdk.ts b/packages/liquidity-sdk/src/wagmi-sdk.ts new file mode 100644 index 0000000..a2a202c --- /dev/null +++ b/packages/liquidity-sdk/src/wagmi-sdk.ts @@ -0,0 +1,39 @@ +import { useEffect, useState } from "react"; +import { usePublicClient, useWalletClient } from "wagmi"; +import type { PublicClient } from "viem"; +import { GooddollarLiquiditySDK } from "./viem-sdk"; + +export function useGooddollarLiquidity() { + const publicClient = usePublicClient() as PublicClient; + const { data: walletClient } = useWalletClient(); + + const [sdk, setSDK] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!publicClient) { + setSDK(null); + setError("Public client not initialized"); + return; + } + + setError(null); + setLoading(true); + + try { + const instance = new GooddollarLiquiditySDK( + publicClient, + walletClient ?? undefined, + ); + setSDK(instance); + } catch (err: any) { + setError(err instanceof Error ? err.message : String(err)); + setSDK(null); + } finally { + setLoading(false); + } + }, [publicClient, walletClient]); + + return { sdk, loading, error }; +} diff --git a/packages/liquidity-sdk/tsconfig.json b/packages/liquidity-sdk/tsconfig.json new file mode 100644 index 0000000..c324639 --- /dev/null +++ b/packages/liquidity-sdk/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "target": "ES2022" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/liquidity-sdk/tsup.config.ts b/packages/liquidity-sdk/tsup.config.ts new file mode 100644 index 0000000..158c45f --- /dev/null +++ b/packages/liquidity-sdk/tsup.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + dts: true, + format: ["esm", "cjs"], + treeshake: true, +}); diff --git a/packages/liquidity-widget/package.json b/packages/liquidity-widget/package.json index 190efa5..32cf17d 100644 --- a/packages/liquidity-widget/package.json +++ b/packages/liquidity-widget/package.json @@ -11,6 +11,7 @@ "main": "./dist/index.global.js", "module": "./dist/index.js", "devDependencies": { + "@goodsdks/liquidity-sdk": "*", "@repo/typescript-config": "workspace:*", "tsup": "^8.3.5", "typescript": "latest" diff --git a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts index b0d92ff..0c3c51d 100644 --- a/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts +++ b/packages/liquidity-widget/src/GooddollarLiquidityWidget.ts @@ -9,10 +9,12 @@ import { TICK_SPACING, DEFAULT_EXPLORER_URL, DEFAULT_APPROVAL_BUFFER, FULL_RANGE_TICK_LOWER, FULL_RANGE_TICK_UPPER, tickToSqrtPrice, -} from './liquidity/constants'; -import type { TxFlowPhase, TxStepInfo, PositionData, PoolData, WidgetTheme } from './liquidity/types'; -import { loadPoolData, loadUserBalancesAndAllowances, getUserPositions, formatBigIntDisplay, formatAmount } from './liquidity/pool-service'; -import { approveToken, addLiquidity, parseTxError } from './liquidity/tx-service'; + GooddollarLiquiditySDK, +} from '@goodsdks/liquidity-sdk'; +import type { PoolData, PositionData } from '@goodsdks/liquidity-sdk'; + +import type { TxFlowPhase, TxStepInfo, WidgetTheme } from './liquidity/types'; +import { formatBigIntDisplay, formatAmount } from './liquidity/format'; import { safeParseEther, validateInputs } from './liquidity/validation'; import { buildTxSteps } from './liquidity/tx-steps'; import { RANGE_PRESETS } from './liquidity/components/lw-range-presets'; @@ -94,6 +96,7 @@ export class GooddollarLiquidityWidget extends LitElement { private walletClient: WalletClient | null = null; private publicClient: PublicClient | null = null; + private sdk: GooddollarLiquiditySDK | null = null; private userAddress: string | null = null; private _refreshTimer: ReturnType | null = null; @@ -393,18 +396,30 @@ export class GooddollarLiquidityWidget extends LitElement { // ── Data Loading ─────────────────────────────────────────────────── - private async refreshData() { + private _ensureSDK(): GooddollarLiquiditySDK | null { if (!this.publicClient) { this.publicClient = createPublicClient({ chain: celo, transport: http(), }) as unknown as PublicClient; } + if (!this.sdk) { + this.sdk = new GooddollarLiquiditySDK(this.publicClient); + } + if (this.walletClient) { + this.sdk.setWalletClient(this.walletClient); + } + return this.sdk; + } + + private async refreshData() { + const sdk = this._ensureSDK(); + if (!sdk) return; this.isLoading = true; try { - const pool = await loadPoolData(this.publicClient); + const pool = await sdk.loadPoolData(); this.poolData = pool; this.currentTick = pool.currentTick; } catch (e) { @@ -414,10 +429,11 @@ export class GooddollarLiquidityWidget extends LitElement { try { if (this.web3Provider && this.web3Provider.isConnected) { this.walletClient = createWalletClient({ chain: celo, transport: custom(this.web3Provider) }); + sdk.setWalletClient(this.walletClient); const accounts = await this.web3Provider.request({ method: 'eth_accounts' }); if (accounts.length > 0) { this.userAddress = accounts[0]; - const data = await loadUserBalancesAndAllowances(this.publicClient, this.userAddress as `0x${string}`); + const data = await sdk.loadUserBalancesAndAllowances(this.userAddress as `0x${string}`); this.gdBalance = data.gdBalance; this.usdgloBalance = data.usdgloBalance; this.gdAllowance = data.gdAllowance; @@ -446,11 +462,11 @@ export class GooddollarLiquidityWidget extends LitElement { } private async _loadPositions() { - if (!this.publicClient || !this.userAddress) return; + const sdk = this.sdk; + if (!sdk || !this.userAddress) return; this.positionsLoading = true; try { - this.positions = await getUserPositions( - this.publicClient, + this.positions = await sdk.getUserPositions( this.userAddress as `0x${string}`, this.currentTick, ); @@ -565,7 +581,8 @@ export class GooddollarLiquidityWidget extends LitElement { // ── Main Transaction Flow ────────────────────────────────────────── async _handleMainAction() { - if (!this.walletClient || !this.publicClient || !this.userAddress) return; + const sdk = this.sdk; + if (!sdk || !this.walletClient || !this.userAddress) return; if (this.txPhase === 'success') { this.txPhase = 'idle'; @@ -577,7 +594,6 @@ export class GooddollarLiquidityWidget extends LitElement { this._validateInputs(true); if (this.inputError) return; - const account = this.userAddress as `0x${string}`; const gdWei = safeParseEther(this.gdInput); const usdgloWei = safeParseEther(this.usdgloInput); @@ -598,8 +614,7 @@ export class GooddollarLiquidityWidget extends LitElement { this.txHash = ''; this.txSteps = updateStep(steps, 0, { status: 'active' }); - const hash = await approveToken( - this.publicClient, this.walletClient, account, + const hash = await sdk.approveToken( GD_TOKEN, gdWei, this.approvalBuffer, { onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-gd'); }, @@ -616,8 +631,7 @@ export class GooddollarLiquidityWidget extends LitElement { this.txHash = ''; this.txSteps = updateStep(steps, 1, { status: 'active' }); - const hash = await approveToken( - this.publicClient, this.walletClient, account, + const hash = await sdk.approveToken( USDGLO_TOKEN, usdgloWei, this.approvalBuffer, { onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-usdglo'); }, @@ -633,8 +647,7 @@ export class GooddollarLiquidityWidget extends LitElement { this.txHash = ''; this.txSteps = updateStep(steps, 2, { status: 'active' }); - const hash = await addLiquidity( - this.publicClient, this.walletClient, account, + const hash = await sdk.addLiquidity( gdWei, usdgloWei, this.tickLower, this.tickUpper, { onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'mint'); }, @@ -655,7 +668,7 @@ export class GooddollarLiquidityWidget extends LitElement { } catch (error: any) { this.txPhase = 'error'; - this.txError = parseTxError(error); + this.txError = GooddollarLiquiditySDK.parseTxError(error); this._emitTxEvent('lw-tx-failed', this.txHash, this.txPhase, error); } } @@ -669,7 +682,7 @@ export class GooddollarLiquidityWidget extends LitElement { } private _emitTxEvent(name: string, hash: string, step: string, error?: any) { - this._emitEvent(name, { hash, step, ...(error ? { error: parseTxError(error) } : {}) }); + this._emitEvent(name, { hash, step, ...(error ? { error: GooddollarLiquiditySDK.parseTxError(error) } : {}) }); } } diff --git a/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts b/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts index 648c4ad..24f22c7 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-pool-info.ts @@ -1,6 +1,6 @@ import { LitElement, html, css } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { POOL_ADDRESS, POOL_FEE } from '../constants'; +import { POOL_ADDRESS, POOL_FEE } from '@goodsdks/liquidity-sdk'; import './lw-tooltip'; diff --git a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts index 21c05e9..61454f7 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts @@ -1,8 +1,8 @@ import { LitElement, html, css } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { formatEther } from 'viem'; -import type { PositionData } from '../types'; -import { IS_GD_TOKEN0 } from '../constants'; +import type { PositionData } from '@goodsdks/liquidity-sdk'; +import { IS_GD_TOKEN0 } from '@goodsdks/liquidity-sdk'; const UBESWAP_POOL_BASE = 'https://app.ubeswap.org/#/pools'; diff --git a/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts b/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts index ee9a131..b930e70 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts @@ -1,8 +1,8 @@ import { LitElement, html, css } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { formatEther } from 'viem'; -import type { PositionData } from '../types'; -import { IS_GD_TOKEN0 } from '../constants'; +import type { PositionData } from '@goodsdks/liquidity-sdk'; +import { IS_GD_TOKEN0 } from '@goodsdks/liquidity-sdk'; import './lw-position-card'; import './lw-tooltip'; diff --git a/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts b/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts index f3db142..f7919ad 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-range-presets.ts @@ -2,9 +2,9 @@ import { LitElement, html, css } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import type { RangePreset } from '../types'; import { - FULL_RANGE_TICK_LOWER, FULL_RANGE_TICK_UPPER, TICK_SPACING, - POOL_FEE, nearestUsableTick, -} from '../constants'; + FULL_RANGE_TICK_LOWER, FULL_RANGE_TICK_UPPER, + nearestUsableTick, +} from '@goodsdks/liquidity-sdk'; import './lw-tooltip'; diff --git a/packages/liquidity-widget/src/liquidity/format.ts b/packages/liquidity-widget/src/liquidity/format.ts new file mode 100644 index 0000000..c0f0fa2 --- /dev/null +++ b/packages/liquidity-widget/src/liquidity/format.ts @@ -0,0 +1,14 @@ +import { formatEther } from 'viem'; + +export function formatBigIntDisplay(num: bigint): string { + if (num === 0n) return '0'; + const [whole, frac = ''] = formatEther(num).split('.'); + const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); + const trimmedFrac = frac.slice(0, 2).replace(/0+$/, ''); + return trimmedFrac ? `${grouped}.${trimmedFrac}` : grouped; +} + +export function formatAmount(num: number): string { + if (num === 0) return '0'; + return num.toFixed(6).replace(/\.?0+$/, ''); +} diff --git a/packages/liquidity-widget/src/liquidity/pool-service.ts b/packages/liquidity-widget/src/liquidity/pool-service.ts deleted file mode 100644 index b06efc4..0000000 --- a/packages/liquidity-widget/src/liquidity/pool-service.ts +++ /dev/null @@ -1,158 +0,0 @@ -import type { PublicClient } from 'viem'; -import { formatEther } from 'viem'; -import { - POOL_ADDRESS, POOL_ABI, POSITION_MANAGER, POSITION_MANAGER_ABI, - GD_TOKEN, USDGLO_TOKEN, POOL_FEE, IS_GD_TOKEN0, TOKEN0, TOKEN1, - ERC20_ABI -} from './constants'; -import { computeGdPriceFromSqrtPrice, computeSqrtPriceFloat } from './price-math'; -import { getAmountsForPositionApprox } from './liquidity-math'; -import type { PoolData, PositionData } from './types'; - -export async function loadPoolData(publicClient: PublicClient): Promise { - const slot0 = await publicClient.readContract({ - address: POOL_ADDRESS, - abi: POOL_ABI, - functionName: 'slot0', - }); - - const sqrtPriceX96 = slot0[0]; - const currentTick = slot0[1]; - const gdPriceInUsdglo = computeGdPriceFromSqrtPrice(sqrtPriceX96); - const sqrtPriceFloat = computeSqrtPriceFloat(sqrtPriceX96); - - return { sqrtPriceX96, currentTick, gdPriceInUsdglo, sqrtPriceFloat }; -} - -export async function loadUserBalancesAndAllowances( - publicClient: PublicClient, - userAddress: `0x${string}`, -) { - const results = await publicClient.multicall({ - contracts: [ - { - address: GD_TOKEN, abi: ERC20_ABI, - functionName: 'balanceOf' as const, args: [userAddress], - }, - { - address: USDGLO_TOKEN, abi: ERC20_ABI, - functionName: 'balanceOf' as const, args: [userAddress], - }, - { - address: GD_TOKEN, abi: ERC20_ABI, - functionName: 'allowance' as const, args: [userAddress, POSITION_MANAGER], - }, - { - address: USDGLO_TOKEN, abi: ERC20_ABI, - functionName: 'allowance' as const, args: [userAddress, POSITION_MANAGER], - }, - ], - }); - - const gdBalance = results[0].status === 'success' ? results[0].result as bigint : 0n; - const usdgloBalance = results[1].status === 'success' ? results[1].result as bigint : 0n; - const gdAllowance = results[2].status === 'success' ? results[2].result as bigint : 0n; - const usdgloAllowance = results[3].status === 'success' ? results[3].result as bigint : 0n; - - return { gdBalance, usdgloBalance, gdAllowance, usdgloAllowance }; -} - -export async function getUserPositions( - publicClient: PublicClient, - userAddress: `0x${string}`, - currentTick: number, -): Promise { - let positionCount: bigint; - try { - positionCount = await publicClient.readContract({ - address: POSITION_MANAGER, - abi: POSITION_MANAGER_ABI, - functionName: 'balanceOf', - args: [userAddress], - }) as bigint; - } catch { - return []; - } - - if (positionCount === 0n) return []; - - const tokenIdResults = await publicClient.multicall({ - contracts: Array.from({ length: Number(positionCount) }, (_, i) => ({ - address: POSITION_MANAGER, - abi: POSITION_MANAGER_ABI, - functionName: 'tokenOfOwnerByIndex' as const, - args: [userAddress, BigInt(i)], - })), - }); - - const tokenIds = tokenIdResults - .filter((r) => r.status === 'success') - .map((r) => r.result as bigint); - - if (tokenIds.length === 0) return []; - - const positionResults = await publicClient.multicall({ - contracts: tokenIds.map((tokenId) => ({ - address: POSITION_MANAGER, - abi: POSITION_MANAGER_ABI, - functionName: 'positions' as const, - args: [tokenId], - })), - }); - - const positions: PositionData[] = []; - for (let i = 0; i < tokenIds.length; i++) { - const res = positionResults[i]; - if (res.status !== 'success') continue; - - const pos = res.result as readonly [bigint, string, string, string, number, number, number, bigint, bigint, bigint, bigint, bigint]; - const [, , token0, token1, fee, tickLower, tickUpper, liquidity, , , tokensOwed0, tokensOwed1] = pos; - - const matchesPool = - token0.toLowerCase() === TOKEN0.toLowerCase() && - token1.toLowerCase() === TOKEN1.toLowerCase() && - fee === POOL_FEE; - - if (!matchesPool) continue; - if (liquidity === 0n && tokensOwed0 === 0n && tokensOwed1 === 0n) continue; - - const { amount0, amount1 } = getAmountsForPositionApprox( - liquidity, tickLower, tickUpper, currentTick, - ); - - positions.push({ - tokenId: tokenIds[i], - token0, token1, - fee, tickLower, tickUpper, - liquidity, - tokensOwed0, tokensOwed1, - amount0, amount1, - inRange: currentTick >= tickLower && currentTick < tickUpper, - }); - } - - return positions; -} - -export function formatBigIntDisplay(num: bigint): string { - if (num === 0n) return '0'; - const [whole, frac = ''] = formatEther(num).split('.'); - const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - const trimmedFrac = frac.slice(0, 2).replace(/0+$/, ''); - return trimmedFrac ? `${grouped}.${trimmedFrac}` : grouped; -} - -export function formatAmount(num: number): string { - if (num === 0) return '0'; - return num.toFixed(6).replace(/\.?0+$/, ''); -} - -export function getGdAndUsdgloAmounts( - amount0: bigint, - amount1: bigint, -): { gdAmount: bigint; usdgloAmount: bigint } { - return { - gdAmount: IS_GD_TOKEN0 ? amount0 : amount1, - usdgloAmount: IS_GD_TOKEN0 ? amount1 : amount0, - }; -} diff --git a/packages/liquidity-widget/src/liquidity/tx-service.ts b/packages/liquidity-widget/src/liquidity/tx-service.ts deleted file mode 100644 index a6ad8b4..0000000 --- a/packages/liquidity-widget/src/liquidity/tx-service.ts +++ /dev/null @@ -1,170 +0,0 @@ -import type { PublicClient, WalletClient } from 'viem'; -import { - POSITION_MANAGER, POSITION_MANAGER_ABI, ERC20_ABI, - TOKEN0, TOKEN1, POOL_FEE, IS_GD_TOKEN0, -} from './constants'; - -const MAX_UINT128 = 2n ** 128n - 1n; - -export interface TxCallbacks { - onHash?: (hash: `0x${string}`) => void; - onConfirmed?: (hash: `0x${string}`) => void; -} - -export async function approveToken( - publicClient: PublicClient, - walletClient: WalletClient, - account: `0x${string}`, - tokenAddress: `0x${string}`, - amount: bigint, - bufferPercent: number = 5, - callbacks?: TxCallbacks, -): Promise<`0x${string}`> { - const bufferedAmount = amount + (amount * BigInt(Math.round(bufferPercent * 100)) / 10000n); - - const { request } = await publicClient.simulateContract({ - account, - address: tokenAddress, - abi: ERC20_ABI, - functionName: 'approve', - args: [POSITION_MANAGER, bufferedAmount], - }); - - const hash = await walletClient.writeContract(request); - callbacks?.onHash?.(hash); - - await publicClient.waitForTransactionReceipt({ hash }); - callbacks?.onConfirmed?.(hash); - - await new Promise((resolve) => setTimeout(resolve, 2000)); - return hash; -} - -export async function addLiquidity( - publicClient: PublicClient, - walletClient: WalletClient, - account: `0x${string}`, - gdAmountWei: bigint, - usdgloAmountWei: bigint, - tickLower: number, - tickUpper: number, - callbacks?: TxCallbacks, -): Promise<`0x${string}`> { - const amount0Desired = IS_GD_TOKEN0 ? gdAmountWei : usdgloAmountWei; - const amount1Desired = IS_GD_TOKEN0 ? usdgloAmountWei : gdAmountWei; - const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); - - const { request } = await publicClient.simulateContract({ - account, - address: POSITION_MANAGER, - abi: POSITION_MANAGER_ABI, - functionName: 'mint', - args: [{ - token0: TOKEN0, - token1: TOKEN1, - fee: POOL_FEE, - tickLower, - tickUpper, - amount0Desired, - amount1Desired, - amount0Min: 0n, - amount1Min: 0n, - recipient: account, - deadline, - }], - }); - - const hash = await walletClient.writeContract(request); - callbacks?.onHash?.(hash); - - await publicClient.waitForTransactionReceipt({ hash }); - callbacks?.onConfirmed?.(hash); - - await new Promise((resolve) => setTimeout(resolve, 2000)); - return hash; -} - -export async function removeLiquidity( - publicClient: PublicClient, - walletClient: WalletClient, - account: `0x${string}`, - tokenId: bigint, - liquidity: bigint, - callbacks?: TxCallbacks, -): Promise<`0x${string}`> { - if (liquidity > MAX_UINT128) { - throw new Error('Liquidity value exceeds uint128 maximum'); - } - - const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200); - - const { request: decreaseReq } = await publicClient.simulateContract({ - account, - address: POSITION_MANAGER, - abi: POSITION_MANAGER_ABI, - functionName: 'decreaseLiquidity', - args: [{ - tokenId, - liquidity: liquidity as unknown as bigint & { __brand: 'uint128' }, - amount0Min: 0n, - amount1Min: 0n, - deadline, - }], - }); - - const hash = await walletClient.writeContract(decreaseReq); - callbacks?.onHash?.(hash); - await publicClient.waitForTransactionReceipt({ hash }); - callbacks?.onConfirmed?.(hash); - - await new Promise((resolve) => setTimeout(resolve, 2000)); - return hash; -} - -export async function collectFees( - publicClient: PublicClient, - walletClient: WalletClient, - account: `0x${string}`, - tokenId: bigint, - callbacks?: TxCallbacks, -): Promise<`0x${string}`> { - const { request } = await publicClient.simulateContract({ - account, - address: POSITION_MANAGER, - abi: POSITION_MANAGER_ABI, - functionName: 'collect', - args: [{ - tokenId, - recipient: account, - amount0Max: MAX_UINT128, - amount1Max: MAX_UINT128, - }], - }); - - const hash = await walletClient.writeContract(request); - callbacks?.onHash?.(hash); - - await publicClient.waitForTransactionReceipt({ hash }); - callbacks?.onConfirmed?.(hash); - - await new Promise((resolve) => setTimeout(resolve, 2000)); - return hash; -} - -export function parseTxError(error: any): string { - const msg = error?.message || error?.toString() || ''; - - if (msg.includes('User rejected') || msg.includes('user rejected') || msg.includes('ACTION_REJECTED')) - return 'Transaction was rejected in your wallet.'; - if (msg.includes('insufficient funds') || msg.includes('InsufficientFunds')) - return 'Insufficient funds to cover gas fees.'; - if (msg.includes('exceeds balance')) - return 'Token balance too low for this transaction.'; - if (msg.includes('UNPREDICTABLE_GAS') || msg.includes('execution reverted')) - return 'Transaction would fail on-chain. Try adjusting your amounts.'; - if (msg.includes('nonce')) - return 'Transaction nonce conflict. Please reset your wallet or wait for pending transactions.'; - - if (msg.length > 120) return 'Transaction failed. Please try again.'; - return msg || 'Transaction failed. Please try again.'; -} diff --git a/packages/liquidity-widget/src/liquidity/types.ts b/packages/liquidity-widget/src/liquidity/types.ts index 910603b..59f513f 100644 --- a/packages/liquidity-widget/src/liquidity/types.ts +++ b/packages/liquidity-widget/src/liquidity/types.ts @@ -23,30 +23,8 @@ export interface RangePreset { concentrationMultiplier: number; } -export interface PositionData { - tokenId: bigint; - token0: string; - token1: string; - fee: number; - tickLower: number; - tickUpper: number; - liquidity: bigint; - tokensOwed0: bigint; - tokensOwed1: bigint; - amount0: bigint; - amount1: bigint; - inRange: boolean; -} - export interface WidgetTheme { primaryColor: string; borderRadius: string; fontFamily: string; } - -export interface PoolData { - sqrtPriceX96: bigint; - currentTick: number; - gdPriceInUsdglo: number; - sqrtPriceFloat: number; -} diff --git a/yarn.lock b/yarn.lock index 680b73d..faa4eeb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2193,10 +2193,26 @@ __metadata: languageName: unknown linkType: soft +"@goodsdks/liquidity-sdk@npm:*, @goodsdks/liquidity-sdk@workspace:packages/liquidity-sdk": + version: 0.0.0-use.local + resolution: "@goodsdks/liquidity-sdk@workspace:packages/liquidity-sdk" + dependencies: + "@repo/typescript-config": "workspace:*" + tsup: "npm:^8.3.5" + typescript: "npm:latest" + viem: "npm:latest" + wagmi: "npm:latest" + peerDependencies: + viem: "*" + wagmi: "*" + languageName: unknown + linkType: soft + "@goodsdks/liquidity-widget@workspace:packages/liquidity-widget": version: 0.0.0-use.local resolution: "@goodsdks/liquidity-widget@workspace:packages/liquidity-widget" dependencies: + "@goodsdks/liquidity-sdk": "npm:*" "@repo/typescript-config": "workspace:*" lit: "npm:^3.1.0" tsup: "npm:^8.3.5" From f2a17305a477bdfb6a7ef72762ff177df5d8bb9c Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Tue, 14 Apr 2026 17:26:40 +0300 Subject: [PATCH 06/11] doc: added liquidity widget react documentation --- packages/liquidity-widget/REACT_DOCUMENT.md | 333 ++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 packages/liquidity-widget/REACT_DOCUMENT.md diff --git a/packages/liquidity-widget/REACT_DOCUMENT.md b/packages/liquidity-widget/REACT_DOCUMENT.md new file mode 100644 index 0000000..7fdf8b6 --- /dev/null +++ b/packages/liquidity-widget/REACT_DOCUMENT.md @@ -0,0 +1,333 @@ +# Using `@goodsdks/liquidity-widget` in React + +The liquidity widget is a [Lit](https://lit.dev) **web component** registered as the custom element ``. Because it is a standard DOM element, it can be dropped into any React app — you just need to pass the wallet plumbing (an EIP-1193 `web3Provider` and a `connectWallet` callback) from your wallet library of choice. + +This guide covers: + +1. [Installation & Registration](#1-installation--registration) +2. [A `` React wrapper](#2-a-liquiditywidget--react-wrapper) +3. [Integrating with wagmi](#3-integrating-with-wagmi) +4. [Integrating with Reown AppKit](#4-integrating-with-reown-appkit) +5. [Listening to widget events](#5-listening-to-widget-events) +6. [TypeScript / JSX support](#6-typescript--jsx-support) + +--- + +## 1. Installation & Registration + +Install the widget and your wallet library: + +```bash +yarn add @goodsdks/liquidity-widget +# pick one (or both) for wallet plumbing: +yarn add wagmi viem @tanstack/react-query +yarn add @reown/appkit @reown/appkit-adapter-wagmi +``` + +Import the package once at the entrypoint of your app. The import has the side effect of registering the `` custom element: + +```tsx +// src/main.tsx (or _app.tsx, etc.) +import "@goodsdks/liquidity-widget"; +``` + +> If you are using Next.js (App Router), register the element inside a client component (`"use client"`) so it is only loaded in the browser. + +--- + +## 2. A `` React wrapper + +Two of the widget's integrator inputs — `web3Provider` and `connectWallet` — are **JS properties**, not HTML attributes. React <19 serializes unknown attributes to strings, so you must set these through a `ref`. The wrapper below handles that and works in both React 18 and 19. + +```tsx +// src/LiquidityWidget.tsx +"use client"; + +import "@goodsdks/liquidity-widget"; +import { useEffect, useRef } from "react"; +import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget/src/GooddollarLiquidityWidget"; + +type WidgetTheme = { + primaryColor?: string; + borderRadius?: string; + fontFamily?: string; +}; + +export type LiquidityWidgetProps = { + web3Provider: unknown | null; + connectWallet?: () => void; + explorerBaseUrl?: string; + approvalBuffer?: number; + defaultRange?: "full" | "wide" | "narrow"; + showPositions?: boolean; + refreshInterval?: number; + theme?: WidgetTheme; + onTxSubmitted?: (detail: { hash: string; step: string }) => void; + onTxConfirmed?: (detail: { hash: string; step: string }) => void; + onTxFailed?: (detail: { hash: string; step: string; error: string }) => void; + onPositionAdded?: (detail: { hash: string }) => void; +}; + +export function LiquidityWidget(props: LiquidityWidgetProps) { + const ref = useRef(null); + + // Set JS properties (not serializable as attributes). + useEffect(() => { + const el = ref.current; + if (!el) return; + el.web3Provider = props.web3Provider ?? null; + el.connectWallet = props.connectWallet; + el.theme = props.theme; + }, [props.web3Provider, props.connectWallet, props.theme]); + + // Forward events. + useEffect(() => { + const el = ref.current; + if (!el) return; + const s = (e: Event) => props.onTxSubmitted?.((e as CustomEvent).detail); + const c = (e: Event) => props.onTxConfirmed?.((e as CustomEvent).detail); + const f = (e: Event) => props.onTxFailed?.((e as CustomEvent).detail); + const p = (e: Event) => props.onPositionAdded?.((e as CustomEvent).detail); + el.addEventListener("lw-tx-submitted", s); + el.addEventListener("lw-tx-confirmed", c); + el.addEventListener("lw-tx-failed", f); + el.addEventListener("lw-position-added", p); + return () => { + el.removeEventListener("lw-tx-submitted", s); + el.removeEventListener("lw-tx-confirmed", c); + el.removeEventListener("lw-tx-failed", f); + el.removeEventListener("lw-position-added", p); + }; + }, [props.onTxSubmitted, props.onTxConfirmed, props.onTxFailed, props.onPositionAdded]); + + return ( + + ); +} +``` + +> Scalar attributes (`explorer-base-url`, `approval-buffer`, …) are fine as HTML attributes — Lit coerces them based on the `@property({ type: ... })` declarations. Object, function, and boolean-as-flag values must go through the ref. + +--- + +## 3. Integrating with wagmi + +wagmi's connectors expose an EIP-1193 provider via `connector.getProvider()`. The widget expects that provider plus a `connectWallet` callback that opens your connect modal. + +```tsx +// src/LiquidityPage.tsx +"use client"; + +import { useEffect, useState } from "react"; +import { useAccount, useConnect, useConnectors, useChainId, useSwitchChain } from "wagmi"; +import { celo } from "wagmi/chains"; +import { LiquidityWidget } from "./LiquidityWidget"; + +export function LiquidityPage() { + const { address, isConnected, connector } = useAccount(); + const { connect } = useConnect(); + const connectors = useConnectors(); + const chainId = useChainId(); + const { switchChain } = useSwitchChain(); + + const [provider, setProvider] = useState(null); + + // Pull the EIP-1193 provider off the active connector. + useEffect(() => { + let cancelled = false; + (async () => { + if (!isConnected || !connector) { + setProvider(null); + return; + } + const p = await connector.getProvider(); + if (!cancelled) setProvider(p); + })(); + return () => { + cancelled = true; + }; + }, [isConnected, connector, address]); + + // Widget pool lives on Celo. + useEffect(() => { + if (isConnected && chainId !== celo.id) switchChain({ chainId: celo.id }); + }, [isConnected, chainId, switchChain]); + + return ( + connect({ connector: connectors[0] })} + onPositionAdded={({ hash }) => console.log("Minted position:", hash)} + theme={{ primaryColor: "#00b0ff", borderRadius: "16px" }} + /> + ); +} +``` + +Wrap your app with a wagmi + react-query provider as usual: + +```tsx +// src/providers.tsx +"use client"; + +import { WagmiProvider, createConfig, http } from "wagmi"; +import { celo } from "wagmi/chains"; +import { injected } from "wagmi/connectors"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +const config = createConfig({ + chains: [celo], + transports: { [celo.id]: http() }, + connectors: [injected()], +}); + +const qc = new QueryClient(); + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} +``` + +> The widget will not send transactions from an account on a network other than Celo. If your app supports multiple chains, switch to Celo before the user interacts with the widget (shown above). + +--- + +## 4. Integrating with Reown AppKit + +AppKit provides its own EIP-1193 provider and connect modal. When using the wagmi adapter, you still reuse the wagmi-based flow from §3 — the widget consumes the provider from wagmi's active connector, and `connectWallet` opens the AppKit modal. + +```tsx +// src/appkit.ts +"use client"; + +import { createAppKit } from "@reown/appkit/react"; +import { WagmiAdapter } from "@reown/appkit-adapter-wagmi"; +import { celo } from "@reown/appkit/networks"; + +const projectId = import.meta.env.VITE_WC_PROJECT_ID!; + +export const wagmiAdapter = new WagmiAdapter({ + projectId, + networks: [celo], +}); + +export const appKit = createAppKit({ + adapters: [wagmiAdapter], + networks: [celo], + projectId, + metadata: { + name: "My dApp", + description: "G$ liquidity", + url: "https://example.com", + icons: [], + }, +}); +``` + +```tsx +// src/LiquidityPage.tsx +"use client"; + +import { useEffect, useState } from "react"; +import { useAppKit, useAppKitAccount, useAppKitProvider } from "@reown/appkit/react"; +import { LiquidityWidget } from "./LiquidityWidget"; + +export function LiquidityPage() { + const { open } = useAppKit(); + const { isConnected } = useAppKitAccount(); + const { walletProvider } = useAppKitProvider("eip155"); + + const [provider, setProvider] = useState(null); + useEffect(() => { + setProvider(isConnected ? walletProvider ?? null : null); + }, [isConnected, walletProvider]); + + return ( + open()} + onPositionAdded={({ hash }) => console.log("Minted:", hash)} + /> + ); +} +``` + +> If you are not using the wagmi adapter, you can subscribe to AppKit directly — see [README.md](./README.md) for the vanilla-JS `appKit.subscribeAccount(...)` pattern. + +--- + +## 5. Listening to widget events + +The widget dispatches four custom DOM events. The wrapper from §2 forwards them as props: + +| Event | Detail | When | +| -------------------- | ---------------------------------------- | ---------------------------- | +| `lw-tx-submitted` | `{ hash, step }` | Wallet returned a tx hash | +| `lw-tx-confirmed` | `{ hash, step }` | Tx confirmed on-chain | +| `lw-tx-failed` | `{ hash, step, error }` | Tx failed or was rejected | +| `lw-position-added` | `{ hash }` | New position minted | + +`step` is one of `approve-gd`, `approve-usdglo`, or `mint`. + +```tsx + analytics.track("lw_submit", { hash, step })} + onPositionAdded={({ hash }) => toast.success(`Minted: ${hash}`)} +/> +``` + +--- + +## 6. TypeScript / JSX support + +Declare the custom element on `JSX.IntrinsicElements` so `` type-checks inside JSX: + +```ts +// src/types/liquidity-widget.d.ts +import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget/src/GooddollarLiquidityWidget"; +import type { DetailedHTMLProps, HTMLAttributes } from "react"; + +declare global { + namespace JSX { + interface IntrinsicElements { + "gooddollar-liquidity-widget": DetailedHTMLProps< + HTMLAttributes & { + "explorer-base-url"?: string; + "approval-buffer"?: number; + "default-range"?: "full" | "wide" | "narrow"; + "show-positions"?: string; + "refresh-interval"?: number; + }, + GooddollarLiquidityWidget + >; + } + } +} +``` + +--- + +## Props reference + +See [README.md](./README.md) for the full list. The most common ones: + +- `web3Provider` — EIP-1193 provider from wagmi / AppKit. `null` when disconnected. +- `connectWallet` — called when the user clicks "Connect Wallet". +- `explorerBaseUrl` — default `https://celoscan.io`. +- `approvalBuffer` — percentage buffer on top of approvals (default `5`). +- `defaultRange` — `"full" | "wide" | "narrow"` (default `"full"`). +- `showPositions` — toggles the "My Positions" tab. +- `refreshInterval` — ms between pool/balance refreshes, `0` to disable. +- `theme` — `{ primaryColor?, borderRadius?, fontFamily? }`. From d922c11a610e6ba3417c33de246a957adc96ab62 Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Thu, 23 Apr 2026 15:09:45 +0300 Subject: [PATCH 07/11] feat: example app for liquidity widget --- apps/demo-liquidity-widget/.eslintrc.json | 23 +++ apps/demo-liquidity-widget/.gitignore | 4 + apps/demo-liquidity-widget/README.md | 45 +++++ apps/demo-liquidity-widget/index.html | 13 ++ apps/demo-liquidity-widget/package.json | 44 +++++ apps/demo-liquidity-widget/public/vite.svg | 1 + apps/demo-liquidity-widget/src/App.tsx | 175 ++++++++++++++++++ .../src/components/LiquidityWidget.tsx | 71 +++++++ apps/demo-liquidity-widget/src/config.tsx | 57 ++++++ apps/demo-liquidity-widget/src/globals.d.ts | 24 +++ apps/demo-liquidity-widget/src/index.css | 73 ++++++++ apps/demo-liquidity-widget/src/main.tsx | 13 ++ apps/demo-liquidity-widget/tsconfig.app.json | 30 +++ apps/demo-liquidity-widget/tsconfig.json | 10 + apps/demo-liquidity-widget/vercel.json | 12 ++ apps/demo-liquidity-widget/vite-env.d.ts | 1 + apps/demo-liquidity-widget/vite.config.mts | 17 ++ yarn.lock | 37 +++- 18 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 apps/demo-liquidity-widget/.eslintrc.json create mode 100644 apps/demo-liquidity-widget/.gitignore create mode 100644 apps/demo-liquidity-widget/README.md create mode 100644 apps/demo-liquidity-widget/index.html create mode 100644 apps/demo-liquidity-widget/package.json create mode 100644 apps/demo-liquidity-widget/public/vite.svg create mode 100644 apps/demo-liquidity-widget/src/App.tsx create mode 100644 apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx create mode 100644 apps/demo-liquidity-widget/src/config.tsx create mode 100644 apps/demo-liquidity-widget/src/globals.d.ts create mode 100644 apps/demo-liquidity-widget/src/index.css create mode 100644 apps/demo-liquidity-widget/src/main.tsx create mode 100644 apps/demo-liquidity-widget/tsconfig.app.json create mode 100644 apps/demo-liquidity-widget/tsconfig.json create mode 100644 apps/demo-liquidity-widget/vercel.json create mode 100644 apps/demo-liquidity-widget/vite-env.d.ts create mode 100644 apps/demo-liquidity-widget/vite.config.mts diff --git a/apps/demo-liquidity-widget/.eslintrc.json b/apps/demo-liquidity-widget/.eslintrc.json new file mode 100644 index 0000000..1eebf9a --- /dev/null +++ b/apps/demo-liquidity-widget/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "root": true, + "env": { + "browser": true, + "es2020": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + "prettier" + ], + "ignorePatterns": [ + "dist", + ".eslintrc.json" + ], + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint", + "react-hooks" + ], + "rules": {} +} diff --git a/apps/demo-liquidity-widget/.gitignore b/apps/demo-liquidity-widget/.gitignore new file mode 100644 index 0000000..91a607b --- /dev/null +++ b/apps/demo-liquidity-widget/.gitignore @@ -0,0 +1,4 @@ +.vercel +.certs +.yalc +yalc.lock diff --git a/apps/demo-liquidity-widget/README.md b/apps/demo-liquidity-widget/README.md new file mode 100644 index 0000000..cf61509 --- /dev/null +++ b/apps/demo-liquidity-widget/README.md @@ -0,0 +1,45 @@ +## Getting Started + +This demo shows how to integrate the `@goodsdks/liquidity-widget` web component +into a React app using [Reown AppKit](https://reown.com/) + [wagmi](https://wagmi.sh). + +1. **Clone the Repository** + + ```bash + git clone https://github.com/GoodDollar/GoodSdks + ``` + +2. **Install & Build** + + From the monorepo root: + + ```bash + yarn install --immutable && yarn build + ``` + +3. **Start the Development Server** + + ```bash + cd apps/demo-liquidity-widget + yarn dev + ``` + +4. **Open the App** + + Visit `http://localhost:3000`. + +## Usage + +The liquidity widget is a Lit-based web component registered as +``. See +[packages/liquidity-widget/REACT_DOCUMENT.md](../../packages/liquidity-widget/REACT_DOCUMENT.md) +for the full React integration guide. + +This demo uses: + +- `src/config.tsx` — Reown AppKit + wagmi setup (Celo only; the pool is on Celo). +- `src/components/LiquidityWidget.tsx` — Thin React wrapper around the web + component that sets the `web3Provider` and `connectWallet` JS properties via + `ref` (non-serializable props can't go through JSX attributes in React <19). +- `src/App.tsx` — Page layout + wagmi plumbing to pull the EIP-1193 provider + off the active connector and pass it to the widget. diff --git a/apps/demo-liquidity-widget/index.html b/apps/demo-liquidity-widget/index.html new file mode 100644 index 0000000..e63f5b3 --- /dev/null +++ b/apps/demo-liquidity-widget/index.html @@ -0,0 +1,13 @@ + + + + + + + GoodDollar Liquidity Widget Demo + + +
+ + + diff --git a/apps/demo-liquidity-widget/package.json b/apps/demo-liquidity-widget/package.json new file mode 100644 index 0000000..4aecb7c --- /dev/null +++ b/apps/demo-liquidity-widget/package.json @@ -0,0 +1,44 @@ +{ + "name": "demo-liquidity-widget", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite --port 3000", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint . --ext .ts,.tsx", + "format": "prettier --write ." + }, + "dependencies": { + "@goodsdks/liquidity-widget": "*", + "@reown/appkit": "^1.7.2", + "@reown/appkit-adapter-wagmi": "^1.7.2", + "@reown/appkit-wallet": "^1.7.2", + "@tamagui/config": "^1.125.22", + "@tamagui/core": "^1.125.22", + "@tamagui/font-inter": "^1.125.22", + "@tamagui/vite-plugin": "^1.125.22", + "@tamagui/web": "^1.125.22", + "@tanstack/react-query": "^4.36.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "tamagui": "^1.125.22", + "viem": "^1.21.4", + "wagmi": "^1.4.13" + }, + "devDependencies": { + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", + "@vitejs/plugin-react": "^4.3.4", + "cross-env": "^7.0.3", + "eslint": "^8.57.1", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react-hooks": "^5.2.0", + "prettier": "^3.5.3", + "typescript": "^5.8.2", + "vite": "6.3.5" + } +} diff --git a/apps/demo-liquidity-widget/public/vite.svg b/apps/demo-liquidity-widget/public/vite.svg new file mode 100644 index 0000000..ee9fada --- /dev/null +++ b/apps/demo-liquidity-widget/public/vite.svg @@ -0,0 +1 @@ + diff --git a/apps/demo-liquidity-widget/src/App.tsx b/apps/demo-liquidity-widget/src/App.tsx new file mode 100644 index 0000000..b37cf50 --- /dev/null +++ b/apps/demo-liquidity-widget/src/App.tsx @@ -0,0 +1,175 @@ +import React, { useEffect, useState } from "react" +import { + createTamagui, + TamaguiProvider, + View, + Text, + ScrollView, + YStack, + Anchor, + Stack, +} from "tamagui" +import { config } from "@tamagui/config/v3" +import { useAppKit } from "@reown/appkit/react" +import { celo } from "wagmi/chains" +import { useAccount, useChainId, useSwitchChain } from "wagmi" + +import { LiquidityWidget } from "./components/LiquidityWidget" + +const tamaguiConfig = createTamagui(config) + +const App: React.FC = () => { + const { open } = useAppKit() + const { address, isConnected, connector } = useAccount() + const chainId = useChainId() + const { switchChain } = useSwitchChain() + + const [provider, setProvider] = useState(null) + + // Pull the EIP-1193 provider off the active connector. + useEffect(() => { + let cancelled = false + ;(async () => { + if (!isConnected || !connector) { + setProvider(null) + return + } + const p = await connector.getProvider() + if (!cancelled) setProvider(p) + })() + return () => { + cancelled = true + } + }, [isConnected, connector, address]) + + // The G$/USDGLO pool is on Celo, so keep the user there. + useEffect(() => { + if (isConnected && chainId !== celo.id) { + switchChain({ chainId: celo.id }) + } + }, [isConnected, chainId, switchChain]) + + return ( + + + + + GoodDollar Liquidity Widget + + + {/* Disclaimer Section */} + + + Disclaimer: + This is a demo showing how to embed the{" "} + {``}{" "} + web component in a React app. It provides liquidity to the + G$/USDGLO pool on Celo.{" "} + + Learn more about the SDK and how to integrate it here. + + + + + {/* Connect Section */} + + + {!isConnected ? ( + + Connect your wallet to add liquidity. + + ) : null} + + + + + {/* Liquidity Widget */} + + open()} + defaultRange="full" + showPositions + onTxSubmitted={({ hash, step }) => + console.log("[lw] submitted", step, hash) + } + onTxConfirmed={({ hash, step }) => + console.log("[lw] confirmed", step, hash) + } + onTxFailed={({ hash, step, error }) => + console.warn("[lw] failed", step, hash, error) + } + onPositionAdded={({ hash }) => + console.log("[lw] position minted", hash) + } + theme={{ primaryColor: "#00BB7F", borderRadius: "16px" }} + /> + + + {/* Help Section */} + + + Need help? Visit our docs:{" "} + + GoodDollar Docs + + . + + + Or join our Developer Communities at:{" "} + + GoodBuilders Discord + + . + + + + + + ) +} + +export default App diff --git a/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx b/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx new file mode 100644 index 0000000..494f818 --- /dev/null +++ b/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx @@ -0,0 +1,71 @@ +import "@goodsdks/liquidity-widget" +import React, { useEffect, useRef } from "react" +import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget/src/GooddollarLiquidityWidget" + +type WidgetTheme = { + primaryColor?: string + borderRadius?: string + fontFamily?: string +} + +export type LiquidityWidgetProps = { + web3Provider: unknown | null + connectWallet?: () => void + explorerBaseUrl?: string + approvalBuffer?: number + defaultRange?: "full" | "wide" | "narrow" + showPositions?: boolean + refreshInterval?: number + theme?: WidgetTheme + onTxSubmitted?: (detail: { hash: string; step: string }) => void + onTxConfirmed?: (detail: { hash: string; step: string }) => void + onTxFailed?: (detail: { hash: string; step: string; error: string }) => void + onPositionAdded?: (detail: { hash: string }) => void +} + +export const LiquidityWidget: React.FC = (props) => { + const ref = useRef(null) + + useEffect(() => { + const el = ref.current + if (!el) return + el.web3Provider = props.web3Provider ?? null + el.connectWallet = props.connectWallet + el.theme = props.theme + }, [props.web3Provider, props.connectWallet, props.theme]) + + useEffect(() => { + const el = ref.current + if (!el) return + const s = (e: Event) => props.onTxSubmitted?.((e as CustomEvent).detail) + const c = (e: Event) => props.onTxConfirmed?.((e as CustomEvent).detail) + const f = (e: Event) => props.onTxFailed?.((e as CustomEvent).detail) + const p = (e: Event) => props.onPositionAdded?.((e as CustomEvent).detail) + el.addEventListener("lw-tx-submitted", s) + el.addEventListener("lw-tx-confirmed", c) + el.addEventListener("lw-tx-failed", f) + el.addEventListener("lw-position-added", p) + return () => { + el.removeEventListener("lw-tx-submitted", s) + el.removeEventListener("lw-tx-confirmed", c) + el.removeEventListener("lw-tx-failed", f) + el.removeEventListener("lw-position-added", p) + } + }, [ + props.onTxSubmitted, + props.onTxConfirmed, + props.onTxFailed, + props.onPositionAdded, + ]) + + return ( + + ) +} diff --git a/apps/demo-liquidity-widget/src/config.tsx b/apps/demo-liquidity-widget/src/config.tsx new file mode 100644 index 0000000..b4357f5 --- /dev/null +++ b/apps/demo-liquidity-widget/src/config.tsx @@ -0,0 +1,57 @@ +import { createAppKit } from "@reown/appkit/react" +import { http, WagmiProvider } from "wagmi" +import { celo, type AppKitNetwork } from "@reown/appkit/networks" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import { WagmiAdapter } from "@reown/appkit-adapter-wagmi" +import React, { ReactNode } from "react" + +const queryClient = new QueryClient() + +const projectId = "71dd03d057d89d0af68a4c627ec59694" + +const metadata = { + name: "GoodDollar Liquidity Demo", + description: "Demo for the @goodsdks/liquidity-widget web component", + url: "https://example.com", + icons: ["https://avatars.githubusercontent.com/u/179229932"], +} + +// The G$/USDGLO pool lives on Celo, so we restrict the demo to that network. +const networks: [AppKitNetwork, ...AppKitNetwork[]] = [celo] + +const wagmiAdapter = new WagmiAdapter({ + networks, + projectId, + ssr: true, + transports: { + [celo.id]: http("https://forno.celo.org"), + }, +}) + +createAppKit({ + adapters: [wagmiAdapter], + networks, + projectId, + metadata, + features: { + analytics: true, + }, + themeMode: "light", + themeVariables: { + "--w3m-color-mix": "#00BB7F", + "--w3m-color-mix-strength": 40, + "--w3m-accent": "#00BB7F", + }, +}) + +type ComponentProps = { + children: ReactNode +} + +export const AppKitProvider: React.FC = ({ children }) => { + return ( + + {children} + + ) +} diff --git a/apps/demo-liquidity-widget/src/globals.d.ts b/apps/demo-liquidity-widget/src/globals.d.ts new file mode 100644 index 0000000..b8d3aa6 --- /dev/null +++ b/apps/demo-liquidity-widget/src/globals.d.ts @@ -0,0 +1,24 @@ +import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget/src/GooddollarLiquidityWidget" +import type { DetailedHTMLProps, HTMLAttributes, Ref } from "react" + +declare global { + namespace JSX { + interface IntrinsicElements { + "appkit-button": React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLElement + > + "gooddollar-liquidity-widget": DetailedHTMLProps< + HTMLAttributes & { + ref?: Ref + "explorer-base-url"?: string + "approval-buffer"?: number + "default-range"?: "full" | "wide" | "narrow" + "show-positions"?: string + "refresh-interval"?: number + }, + GooddollarLiquidityWidget + > + } + } +} diff --git a/apps/demo-liquidity-widget/src/index.css b/apps/demo-liquidity-widget/src/index.css new file mode 100644 index 0000000..0c4000e --- /dev/null +++ b/apps/demo-liquidity-widget/src/index.css @@ -0,0 +1,73 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: "auto"; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} + +#app { + margin: auto; + width: 100%; +} diff --git a/apps/demo-liquidity-widget/src/main.tsx b/apps/demo-liquidity-widget/src/main.tsx new file mode 100644 index 0000000..7c84355 --- /dev/null +++ b/apps/demo-liquidity-widget/src/main.tsx @@ -0,0 +1,13 @@ +import React from "react" +import ReactDOM from "react-dom/client" +import { AppKitProvider } from "@/config" +import App from "./App" +import "./index.css" + +ReactDOM.createRoot(document.getElementById("app") as HTMLElement).render( + + + + + , +) diff --git a/apps/demo-liquidity-widget/tsconfig.app.json b/apps/demo-liquidity-widget/tsconfig.app.json new file mode 100644 index 0000000..9f0a512 --- /dev/null +++ b/apps/demo-liquidity-widget/tsconfig.app.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/apps/demo-liquidity-widget/tsconfig.json b/apps/demo-liquidity-widget/tsconfig.json new file mode 100644 index 0000000..f036765 --- /dev/null +++ b/apps/demo-liquidity-widget/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@repo/typescript-config/vite.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/apps/demo-liquidity-widget/vercel.json b/apps/demo-liquidity-widget/vercel.json new file mode 100644 index 0000000..641d1ed --- /dev/null +++ b/apps/demo-liquidity-widget/vercel.json @@ -0,0 +1,12 @@ +{ + "buildCommand": "turbo build", + "git": { + "deploymentEnabled": false + }, + "rewrites": [ + { + "source": "/(.*)", + "destination": "/" + } + ] +} diff --git a/apps/demo-liquidity-widget/vite-env.d.ts b/apps/demo-liquidity-widget/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/apps/demo-liquidity-widget/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/demo-liquidity-widget/vite.config.mts b/apps/demo-liquidity-widget/vite.config.mts new file mode 100644 index 0000000..a3720da --- /dev/null +++ b/apps/demo-liquidity-widget/vite.config.mts @@ -0,0 +1,17 @@ +import { defineConfig } from "vite"; +import path from "path"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + resolve: { + dedupe: ["react", "react-dom", "wagmi", "viem"], + alias: { + "@": path.resolve(__dirname, "/src"), + }, + }, + plugins: [react()], + define: { + "process.browser": true, + "process.env": process.env, + }, +}); diff --git a/yarn.lock b/yarn.lock index faa4eeb..86932d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2208,7 +2208,7 @@ __metadata: languageName: unknown linkType: soft -"@goodsdks/liquidity-widget@workspace:packages/liquidity-widget": +"@goodsdks/liquidity-widget@npm:*, @goodsdks/liquidity-widget@workspace:packages/liquidity-widget": version: 0.0.0-use.local resolution: "@goodsdks/liquidity-widget@workspace:packages/liquidity-widget" dependencies: @@ -10612,6 +10612,41 @@ __metadata: languageName: unknown linkType: soft +"demo-liquidity-widget@workspace:apps/demo-liquidity-widget": + version: 0.0.0-use.local + resolution: "demo-liquidity-widget@workspace:apps/demo-liquidity-widget" + dependencies: + "@goodsdks/liquidity-widget": "npm:*" + "@reown/appkit": "npm:^1.7.2" + "@reown/appkit-adapter-wagmi": "npm:^1.7.2" + "@reown/appkit-wallet": "npm:^1.7.2" + "@tamagui/config": "npm:^1.125.22" + "@tamagui/core": "npm:^1.125.22" + "@tamagui/font-inter": "npm:^1.125.22" + "@tamagui/vite-plugin": "npm:^1.125.22" + "@tamagui/web": "npm:^1.125.22" + "@tanstack/react-query": "npm:^4.36.1" + "@types/react": "npm:^18.3.18" + "@types/react-dom": "npm:^18.3.5" + "@typescript-eslint/eslint-plugin": "npm:^5.62.0" + "@typescript-eslint/parser": "npm:^5.62.0" + "@vitejs/plugin-react": "npm:^4.3.4" + cross-env: "npm:^7.0.3" + eslint: "npm:^8.57.1" + eslint-config-prettier: "npm:^8.10.0" + eslint-plugin-react: "npm:^7.37.4" + eslint-plugin-react-hooks: "npm:^5.2.0" + prettier: "npm:^3.5.3" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + tamagui: "npm:^1.125.22" + typescript: "npm:^5.8.2" + viem: "npm:^1.21.4" + vite: "npm:6.3.5" + wagmi: "npm:^1.4.13" + languageName: unknown + linkType: soft + "demo-reserve-swap@workspace:apps/demo-reserve-swap": version: 0.0.0-use.local resolution: "demo-reserve-swap@workspace:apps/demo-reserve-swap" From e89dd6b7ed30bd69673c5f62f82c0d540f4ea321 Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Thu, 23 Apr 2026 17:37:52 +0300 Subject: [PATCH 08/11] refactor: minimize unnecessary number conversion --- packages/liquidity-sdk/src/constants.ts | 4 - packages/liquidity-sdk/src/liquidity-math.ts | 127 ++++++++++++++----- packages/liquidity-sdk/src/price-math.ts | 28 ---- packages/liquidity-sdk/src/viem-sdk.ts | 13 +- 4 files changed, 100 insertions(+), 72 deletions(-) delete mode 100644 packages/liquidity-sdk/src/price-math.ts diff --git a/packages/liquidity-sdk/src/constants.ts b/packages/liquidity-sdk/src/constants.ts index 4768690..1c31855 100644 --- a/packages/liquidity-sdk/src/constants.ts +++ b/packages/liquidity-sdk/src/constants.ts @@ -35,10 +35,6 @@ export const POSITION_MANAGER_ABI = parseAbi([ 'function collect((uint256 tokenId, address recipient, uint128 amount0Max, uint128 amount1Max) params) payable returns (uint256 amount0, uint256 amount1)', ]); -export function tickToSqrtPrice(tick: number): number { - return Math.sqrt(1.0001 ** tick); -} - export function nearestUsableTick(tick: number, spacing: number): number { const rounded = Math.round(tick / spacing) * spacing; return rounded; diff --git a/packages/liquidity-sdk/src/liquidity-math.ts b/packages/liquidity-sdk/src/liquidity-math.ts index 9f8ccb3..6f67b63 100644 --- a/packages/liquidity-sdk/src/liquidity-math.ts +++ b/packages/liquidity-sdk/src/liquidity-math.ts @@ -1,11 +1,56 @@ -import { tickToSqrtPrice } from './constants'; +import { formatEther } from 'viem'; +import { IS_GD_TOKEN0 } from './constants'; + +const MAX_TICK = 887272n; +const MAX_UINT256 = (1n << 256n) - 1n; +const Q96 = 2n ** 96n; +const Q192 = 2n ** 192n; +const SCALE = 10n ** 18n; + +/** + * Port of Uniswap V3 `TickMath.getSqrtRatioAtTick`. Returns the sqrtPriceX96 + * (Q64.96) for a given tick using pure bigint arithmetic, matching the + * on-chain result exactly. + */ +function getSqrtRatioAtTick(tick: number): bigint { + const tickBig = BigInt(tick); + const absTick = tickBig < 0n ? -tickBig : tickBig; + if (absTick > MAX_TICK) throw new Error(`Tick out of bounds: ${tick}`); + + let ratio = + (absTick & 0x1n) !== 0n + ? 0xfffcb933bd6fad37aa2d162d1a594001n + : 0x100000000000000000000000000000000n; + if ((absTick & 0x2n) !== 0n) ratio = (ratio * 0xfff97272373d413259a46990580e213an) >> 128n; + if ((absTick & 0x4n) !== 0n) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdccn) >> 128n; + if ((absTick & 0x8n) !== 0n) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0n) >> 128n; + if ((absTick & 0x10n) !== 0n) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644n) >> 128n; + if ((absTick & 0x20n) !== 0n) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0n) >> 128n; + if ((absTick & 0x40n) !== 0n) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861n) >> 128n; + if ((absTick & 0x80n) !== 0n) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053n) >> 128n; + if ((absTick & 0x100n) !== 0n) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4n) >> 128n; + if ((absTick & 0x200n) !== 0n) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54n) >> 128n; + if ((absTick & 0x400n) !== 0n) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3n) >> 128n; + if ((absTick & 0x800n) !== 0n) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9n) >> 128n; + if ((absTick & 0x1000n) !== 0n) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825n) >> 128n; + if ((absTick & 0x2000n) !== 0n) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5n) >> 128n; + if ((absTick & 0x4000n) !== 0n) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7n) >> 128n; + if ((absTick & 0x8000n) !== 0n) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6n) >> 128n; + if ((absTick & 0x10000n) !== 0n) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9n) >> 128n; + if ((absTick & 0x20000n) !== 0n) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604n) >> 128n; + if ((absTick & 0x40000n) !== 0n) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98n) >> 128n; + if ((absTick & 0x80000n) !== 0n) ratio = (ratio * 0x48a170391f7dc42444e8fa2n) >> 128n; + + if (tickBig > 0n) ratio = MAX_UINT256 / ratio; + + // Convert from Q128.128 to Q128.96, rounding up so the inverse maps cleanly. + return (ratio >> 32n) + (ratio % (1n << 32n) === 0n ? 0n : 1n); +} /** - * Approximate token amounts held by a Uniswap V3 position. - * - * This is a UI-grade approximation: liquidity (uint128) may exceed - * `Number.MAX_SAFE_INTEGER`, so we scale it down before converting to float - * and multiply the result back up to avoid silent overflow/precision loss. + * Approximate token amounts held by a Uniswap V3 position, computed entirely + * with bigint arithmetic against sqrtPriceX96 values so there is no float + * rounding or uint128 scaling hack. */ export function getAmountsForPositionApprox( liquidity: bigint, @@ -15,36 +60,50 @@ export function getAmountsForPositionApprox( ): { amount0: bigint; amount1: bigint } { if (liquidity === 0n) return { amount0: 0n, amount1: 0n }; - let scaleFactor = 1n; - let scaled = liquidity; - while (scaled > BigInt(Number.MAX_SAFE_INTEGER)) { - scaled /= 10n; - scaleFactor *= 10n; - } - const L = Number(scaled); - - const sqrtPriceLower = tickToSqrtPrice(tickLower); - const sqrtPriceUpper = tickToSqrtPrice(tickUpper); - const sqrtPriceCurrent = tickToSqrtPrice(currentTick); - - let amount0 = 0; - let amount1 = 0; + const sqrtPriceLowerX96 = getSqrtRatioAtTick(tickLower); + const sqrtPriceUpperX96 = getSqrtRatioAtTick(tickUpper); if (currentTick < tickLower) { - amount0 = - (L * (sqrtPriceUpper - sqrtPriceLower)) / - (sqrtPriceLower * sqrtPriceUpper); - } else if (currentTick >= tickUpper) { - amount1 = L * (sqrtPriceUpper - sqrtPriceLower); - } else { - amount0 = - (L * (sqrtPriceUpper - sqrtPriceCurrent)) / - (sqrtPriceCurrent * sqrtPriceUpper); - amount1 = L * (sqrtPriceCurrent - sqrtPriceLower); + const amount0 = + (liquidity * (sqrtPriceUpperX96 - sqrtPriceLowerX96) * Q96) / + (sqrtPriceLowerX96 * sqrtPriceUpperX96); + return { amount0, amount1: 0n }; + } + + if (currentTick >= tickUpper) { + const amount1 = + (liquidity * (sqrtPriceUpperX96 - sqrtPriceLowerX96)) / Q96; + return { amount0: 0n, amount1 }; } - return { - amount0: BigInt(Math.max(0, Math.floor(amount0))) * scaleFactor, - amount1: BigInt(Math.max(0, Math.floor(amount1))) * scaleFactor, - }; + const sqrtPriceCurrentX96 = getSqrtRatioAtTick(currentTick); + const amount0 = + (liquidity * (sqrtPriceUpperX96 - sqrtPriceCurrentX96) * Q96) / + (sqrtPriceCurrentX96 * sqrtPriceUpperX96); + const amount1 = + (liquidity * (sqrtPriceCurrentX96 - sqrtPriceLowerX96)) / Q96; + return { amount0, amount1 }; +} + +/** + * Compute the G$ price in USDGLO from the on-chain sqrtPriceX96. + * All intermediate math is done in bigint to avoid uint160 overflow; + * only the final scaled result is converted to a JS number. + */ +export function computeGdPriceFromSqrtPrice(sqrtPriceX96: bigint): number { + if (sqrtPriceX96 === 0n) return 0; + const scaledPrice = (sqrtPriceX96 * sqrtPriceX96 * SCALE) / Q192; + const rawPrice = Number(formatEther(scaledPrice)); + if (rawPrice <= 0) return 0; + return IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice; } + +/** + * Compute the human-scale sqrtPrice float (= sqrtPriceX96 / 2^96) in bigint, + * converting to a JS number only at the end. + */ +export function computeSqrtPriceFloat(sqrtPriceX96: bigint): number { + if (sqrtPriceX96 === 0n) return 0; + const scaled = (sqrtPriceX96 * SCALE) / Q96; + return Number(formatEther(scaled)); +} \ No newline at end of file diff --git a/packages/liquidity-sdk/src/price-math.ts b/packages/liquidity-sdk/src/price-math.ts deleted file mode 100644 index 36e76cb..0000000 --- a/packages/liquidity-sdk/src/price-math.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { IS_GD_TOKEN0 } from './constants'; - -const Q96 = 2n ** 96n; -const Q192 = 2n ** 192n; -const SCALE = 10n ** 18n; - -/** - * Compute the G$ price in USDGLO from the on-chain sqrtPriceX96. - * All intermediate math is done in bigint to avoid uint160 overflow; - * only the final scaled result is converted to a JS number. - */ -export function computeGdPriceFromSqrtPrice(sqrtPriceX96: bigint): number { - if (sqrtPriceX96 === 0n) return 0; - const scaledPrice = (sqrtPriceX96 * sqrtPriceX96 * SCALE) / Q192; - const rawPrice = Number(scaledPrice) / 1e18; - if (rawPrice <= 0) return 0; - return IS_GD_TOKEN0 ? rawPrice : 1 / rawPrice; -} - -/** - * Compute the human-scale sqrtPrice float (= sqrtPriceX96 / 2^96) in bigint, - * converting to a JS number only at the end. - */ -export function computeSqrtPriceFloat(sqrtPriceX96: bigint): number { - if (sqrtPriceX96 === 0n) return 0; - const scaled = (sqrtPriceX96 * SCALE) / Q96; - return Number(scaled) / 1e18; -} diff --git a/packages/liquidity-sdk/src/viem-sdk.ts b/packages/liquidity-sdk/src/viem-sdk.ts index c3f024c..64880fb 100644 --- a/packages/liquidity-sdk/src/viem-sdk.ts +++ b/packages/liquidity-sdk/src/viem-sdk.ts @@ -12,8 +12,7 @@ import { TOKEN1, USDGLO_TOKEN, } from './constants'; -import { computeGdPriceFromSqrtPrice, computeSqrtPriceFloat } from './price-math'; -import { getAmountsForPositionApprox } from './liquidity-math'; +import { computeGdPriceFromSqrtPrice, computeSqrtPriceFloat, getAmountsForPositionApprox } from './liquidity-math'; import type { PoolData, PositionData, @@ -108,22 +107,24 @@ export class GooddollarLiquiditySDK { userAddress: `0x${string}`, currentTick: number, ): Promise { - let positionCount: bigint; + let positionCount: number; try { - positionCount = (await this.publicClient.readContract({ + const positionCountR = (await this.publicClient.readContract({ address: POSITION_MANAGER, abi: POSITION_MANAGER_ABI, functionName: 'balanceOf', args: [userAddress], })) as bigint; + // it is ok to convert to number because position count is in safe range + positionCount = Number(positionCountR); } catch { return []; } - if (positionCount === 0n) return []; + if (positionCount === 0) return []; const tokenIdResults = await this.publicClient.multicall({ - contracts: Array.from({ length: Number(positionCount) }, (_, i) => ({ + contracts: Array.from({ length: positionCount }, (_, i) => ({ address: POSITION_MANAGER, abi: POSITION_MANAGER_ABI, functionName: 'tokenOfOwnerByIndex' as const, From f266fed47cc7cd1f1d44a5f0fbb56325c0b7446d Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Thu, 23 Apr 2026 20:50:09 +0300 Subject: [PATCH 09/11] refactor: format function and calc functions --- .../src/components/LiquidityWidget.tsx | 2 +- packages/liquidity-sdk/src/constants.ts | 4 + packages/liquidity-sdk/src/index.ts | 1 - packages/liquidity-sdk/src/liquidity-math.ts | 75 +++++++++++++- packages/liquidity-widget/REACT_DOCUMENT.md | 18 ++-- packages/liquidity-widget/package.json | 8 ++ .../src/GooddollarLiquidityWidget.ts | 98 +++++++------------ .../liquidity/components/lw-position-card.ts | 8 +- .../liquidity-widget/src/liquidity/format.ts | 14 --- .../src/liquidity/tx-steps.ts | 10 ++ tsconfig.json | 2 + 11 files changed, 149 insertions(+), 91 deletions(-) delete mode 100644 packages/liquidity-widget/src/liquidity/format.ts diff --git a/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx b/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx index 494f818..2edb1ae 100644 --- a/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx +++ b/apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx @@ -1,6 +1,6 @@ import "@goodsdks/liquidity-widget" import React, { useEffect, useRef } from "react" -import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget/src/GooddollarLiquidityWidget" +import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget" type WidgetTheme = { primaryColor?: string diff --git a/packages/liquidity-sdk/src/constants.ts b/packages/liquidity-sdk/src/constants.ts index 1c31855..de50da6 100644 --- a/packages/liquidity-sdk/src/constants.ts +++ b/packages/liquidity-sdk/src/constants.ts @@ -39,3 +39,7 @@ export function nearestUsableTick(tick: number, spacing: number): number { const rounded = Math.round(tick / spacing) * spacing; return rounded; } + +export function tickToSqrtPrice(tick: number): number { + return Math.sqrt(1.0001 ** tick); +} diff --git a/packages/liquidity-sdk/src/index.ts b/packages/liquidity-sdk/src/index.ts index 8e05108..0746b0d 100644 --- a/packages/liquidity-sdk/src/index.ts +++ b/packages/liquidity-sdk/src/index.ts @@ -1,7 +1,6 @@ export * from "./viem-sdk"; export { useGooddollarLiquidity } from "./wagmi-sdk"; export * from "./constants"; -export * from "./price-math"; export * from "./liquidity-math"; export type { PoolData, diff --git a/packages/liquidity-sdk/src/liquidity-math.ts b/packages/liquidity-sdk/src/liquidity-math.ts index 6f67b63..a556967 100644 --- a/packages/liquidity-sdk/src/liquidity-math.ts +++ b/packages/liquidity-sdk/src/liquidity-math.ts @@ -1,5 +1,5 @@ import { formatEther } from 'viem'; -import { IS_GD_TOKEN0 } from './constants'; +import { IS_GD_TOKEN0, tickToSqrtPrice } from './constants'; const MAX_TICK = 887272n; const MAX_UINT256 = (1n << 256n) - 1n; @@ -106,4 +106,77 @@ export function computeSqrtPriceFloat(sqrtPriceX96: bigint): number { if (sqrtPriceX96 === 0n) return 0; const scaled = (sqrtPriceX96 * SCALE) / Q96; return Number(formatEther(scaled)); +} + +function calcAmount1From0( + amount0: number, + sqrtPriceFloat: number, + tickLower: number, + tickUpper: number, +): number { + const sqC = sqrtPriceFloat; + const sqL = tickToSqrtPrice(tickLower); + const sqU = tickToSqrtPrice(tickUpper); + if (sqU <= sqL || sqC <= sqL || sqC >= sqU) return 0; + const L = (amount0 * sqC * sqU) / (sqU - sqC); + return L * (sqC - sqL); +} + +function calcAmount0From1( + amount1: number, + sqrtPriceFloat: number, + tickLower: number, + tickUpper: number, +): number { + const sqC = sqrtPriceFloat; + const sqL = tickToSqrtPrice(tickLower); + const sqU = tickToSqrtPrice(tickUpper); + if (sqU <= sqL || sqC >= sqU || sqC <= sqL) return 0; + const L = amount1 / (sqC - sqL); + return (L * (sqU - sqC)) / (sqC * sqU); +} + +function formatAmount(num: number): string { + if (num === 0) return '0'; + return num.toFixed(6).replace(/\.?0+$/, ''); +} + +/** + * Compute the counterpart USDGLO amount for a given G$ input, using the current + * pool sqrtPrice and the selected tick range. Returns an empty string when the + * input or pool state is invalid. + */ +export function calcUsdgloFromGd( + gd: string, + sqrtPriceFloat: number, + tickLower: number, + tickUpper: number, +): string { + const gdNum = parseFloat(gd); + if (isNaN(gdNum) || gdNum <= 0 || sqrtPriceFloat <= 0) return ''; + const usdglo = IS_GD_TOKEN0 + ? calcAmount1From0(gdNum, sqrtPriceFloat, tickLower, tickUpper) + : calcAmount0From1(gdNum, sqrtPriceFloat, tickLower, tickUpper); + if (!isFinite(usdglo) || usdglo < 0) return ''; + return formatAmount(usdglo); +} + +/** + * Compute the counterpart G$ amount for a given USDGLO input, using the current + * pool sqrtPrice and the selected tick range. Returns an empty string when the + * input or pool state is invalid. + */ +export function calcGdFromUsdglo( + usdglo: string, + sqrtPriceFloat: number, + tickLower: number, + tickUpper: number, +): string { + const u = parseFloat(usdglo); + if (isNaN(u) || u <= 0 || sqrtPriceFloat <= 0) return ''; + const gd = IS_GD_TOKEN0 + ? calcAmount0From1(u, sqrtPriceFloat, tickLower, tickUpper) + : calcAmount1From0(u, sqrtPriceFloat, tickLower, tickUpper); + if (!isFinite(gd) || gd < 0) return ''; + return formatAmount(gd); } \ No newline at end of file diff --git a/packages/liquidity-widget/REACT_DOCUMENT.md b/packages/liquidity-widget/REACT_DOCUMENT.md index 7fdf8b6..97d7f70 100644 --- a/packages/liquidity-widget/REACT_DOCUMENT.md +++ b/packages/liquidity-widget/REACT_DOCUMENT.md @@ -4,12 +4,14 @@ The liquidity widget is a [Lit](https://lit.dev) **web component** registered as This guide covers: -1. [Installation & Registration](#1-installation--registration) -2. [A `` React wrapper](#2-a-liquiditywidget--react-wrapper) -3. [Integrating with wagmi](#3-integrating-with-wagmi) -4. [Integrating with Reown AppKit](#4-integrating-with-reown-appkit) -5. [Listening to widget events](#5-listening-to-widget-events) -6. [TypeScript / JSX support](#6-typescript--jsx-support) +- [Using `@goodsdks/liquidity-widget` in React](#using-goodsdksliquidity-widget-in-react) + - [1. Installation \& Registration](#1-installation--registration) + - [2. A `` React wrapper](#2-a-liquiditywidget--react-wrapper) + - [3. Integrating with wagmi](#3-integrating-with-wagmi) + - [4. Integrating with Reown AppKit](#4-integrating-with-reown-appkit) + - [5. Listening to widget events](#5-listening-to-widget-events) + - [6. TypeScript / JSX support](#6-typescript--jsx-support) + - [Props reference](#props-reference) --- @@ -45,7 +47,7 @@ Two of the widget's integrator inputs — `web3Provider` and `connectWallet` — import "@goodsdks/liquidity-widget"; import { useEffect, useRef } from "react"; -import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget/src/GooddollarLiquidityWidget"; +import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget"; type WidgetTheme = { primaryColor?: string; @@ -296,7 +298,7 @@ Declare the custom element on `JSX.IntrinsicElements` so `, -): TxStepInfo[] { - const next = steps.slice(); - next[index] = { ...next[index], ...patch }; - return next; -} - @customElement('gooddollar-liquidity-widget') export class GooddollarLiquidityWidget extends LitElement { @@ -248,6 +237,11 @@ export class GooddollarLiquidityWidget extends LitElement { // ── Render ───────────────────────────────────────────────────────── + private _fmt(num: bigint): string { + if (num === 0n) return '0'; + return Number(formatEther(num)).toLocaleString('en-US', { maximumFractionDigits: 2 }); + } + render() { const isConnected = !!(this.web3Provider && this.web3Provider.isConnected && this.userAddress); const gdPrice = this.poolData?.gdPriceInUsdglo ?? 0; @@ -312,7 +306,7 @@ export class GooddollarLiquidityWidget extends LitElement { - Balance: ${this.isLoading ? 'Loading...' : formatBigIntDisplay(this.gdBalance)} + Balance: ${this.isLoading ? 'Loading...' : this._fmt(this.gdBalance)}
@@ -332,7 +326,7 @@ export class GooddollarLiquidityWidget extends LitElement { - Balance: ${this.isLoading ? 'Loading...' : formatBigIntDisplay(this.usdgloBalance)} + Balance: ${this.isLoading ? 'Loading...' : this._fmt(this.usdgloBalance)}
@@ -476,40 +470,6 @@ export class GooddollarLiquidityWidget extends LitElement { this.positionsLoading = false; } - // ── Price & Amount Math ──────────────────────────────────────────── - - private _calcAmount1From0(amount0: number): number { - const sqC = this.poolData?.sqrtPriceFloat ?? 0; - const sqL = tickToSqrtPrice(this.tickLower); - const sqU = tickToSqrtPrice(this.tickUpper); - if (sqU <= sqL || sqC <= sqL || sqC >= sqU) return 0; - const L = amount0 * sqC * sqU / (sqU - sqC); - return L * (sqC - sqL); - } - - private _calcAmount0From1(amount1: number): number { - const sqC = this.poolData?.sqrtPriceFloat ?? 0; - const sqL = tickToSqrtPrice(this.tickLower); - const sqU = tickToSqrtPrice(this.tickUpper); - if (sqU <= sqL || sqC >= sqU || sqC <= sqL) return 0; - const L = amount1 / (sqC - sqL); - return L * (sqU - sqC) / (sqC * sqU); - } - - private _calcUsdgloFromGd() { - const gd = parseFloat(this.gdInput); - if (isNaN(gd) || gd <= 0 || !this.poolData) { this.usdgloInput = ''; return; } - const usdglo = IS_GD_TOKEN0 ? this._calcAmount1From0(gd) : this._calcAmount0From1(gd); - if (isFinite(usdglo) && usdglo >= 0) this.usdgloInput = formatAmount(usdglo); - } - - private _calcGdFromUsdglo() { - const u = parseFloat(this.usdgloInput); - if (isNaN(u) || u <= 0 || !this.poolData) { this.gdInput = ''; return; } - const gd = IS_GD_TOKEN0 ? this._calcAmount0From1(u) : this._calcAmount1From0(u); - if (isFinite(gd) && gd >= 0) this.gdInput = formatAmount(gd); - } - // ── Validation ───────────────────────────────────────────────────── private _validateInputs(force = false) { @@ -537,27 +497,43 @@ export class GooddollarLiquidityWidget extends LitElement { private _handleConnect() { this.connectWallet?.(); } + private get _sqrtPriceFloat(): number { + return this.poolData?.sqrtPriceFloat ?? 0; + } + + private _syncUsdgloFromGd() { + this.usdgloInput = calcUsdgloFromGd( + this.gdInput, this._sqrtPriceFloat, this.tickLower, this.tickUpper, + ); + } + + private _syncGdFromUsdglo() { + this.gdInput = calcGdFromUsdglo( + this.usdgloInput, this._sqrtPriceFloat, this.tickLower, this.tickUpper, + ); + } + private _handleGdInput(e: Event) { this.gdInput = (e.target as HTMLInputElement).value; - this._calcUsdgloFromGd(); + this._syncUsdgloFromGd(); this._validateInputs(); } private _handleUsdgloInput(e: Event) { this.usdgloInput = (e.target as HTMLInputElement).value; - this._calcGdFromUsdglo(); + this._syncGdFromUsdglo(); this._validateInputs(); } private _handleGdMax() { this.gdInput = formatEther(this.gdBalance); - this._calcUsdgloFromGd(); + this._syncUsdgloFromGd(); this.inputError = ''; } private _handleUsdgloMax() { this.usdgloInput = formatEther(this.usdgloBalance); - this._calcGdFromUsdglo(); + this._syncGdFromUsdglo(); this.inputError = ''; } @@ -568,7 +544,7 @@ export class GooddollarLiquidityWidget extends LitElement { const { tickLower, tickUpper } = preset.getTickRange(this.currentTick, TICK_SPACING); this.tickLower = tickLower; this.tickUpper = tickUpper; - this._calcUsdgloFromGd(); + this._syncUsdgloFromGd(); } private _handleRetry() { @@ -617,8 +593,8 @@ export class GooddollarLiquidityWidget extends LitElement { const hash = await sdk.approveToken( GD_TOKEN, gdWei, this.approvalBuffer, { - onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-gd'); }, - onConfirmed: (h) => this._emitTxEvent('lw-tx-confirmed', h, 'approve-gd'), + onHash: (h:any) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-gd'); }, + onConfirmed: (h:any) => this._emitTxEvent('lw-tx-confirmed', h, 'approve-gd'), }, ); @@ -634,8 +610,8 @@ export class GooddollarLiquidityWidget extends LitElement { const hash = await sdk.approveToken( USDGLO_TOKEN, usdgloWei, this.approvalBuffer, { - onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-usdglo'); }, - onConfirmed: (h) => this._emitTxEvent('lw-tx-confirmed', h, 'approve-usdglo'), + onHash: (h:any) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'approve-usdglo'); }, + onConfirmed: (h:any) => this._emitTxEvent('lw-tx-confirmed', h, 'approve-usdglo'), }, ); @@ -650,8 +626,8 @@ export class GooddollarLiquidityWidget extends LitElement { const hash = await sdk.addLiquidity( gdWei, usdgloWei, this.tickLower, this.tickUpper, { - onHash: (h) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'mint'); }, - onConfirmed: (h) => this._emitTxEvent('lw-tx-confirmed', h, 'mint'), + onHash: (h:any) => { this.txHash = h; this._emitTxEvent('lw-tx-submitted', h, 'mint'); }, + onConfirmed: (h:any) => this._emitTxEvent('lw-tx-confirmed', h, 'mint'), }, ); diff --git a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts index 61454f7..e529df6 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-position-card.ts @@ -117,11 +117,9 @@ export class LwPositionCard extends LitElement { private _fmt(val: bigint): string { if (val === 0n) return '0'; - const [whole, frac = ''] = formatEther(val).split('.'); - if (whole === '0' && !/[1-9]/.test(frac.slice(0, 4))) return '<0.0001'; - const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - const trimmedFrac = frac.slice(0, 4).replace(/0+$/, ''); - return trimmedFrac ? `${grouped}.${trimmedFrac}` : grouped; + const num = Number(formatEther(val)); + if (num < 0.0001) return '<0.0001'; + return num.toLocaleString('en-US', { maximumFractionDigits: 4 }); } render() { diff --git a/packages/liquidity-widget/src/liquidity/format.ts b/packages/liquidity-widget/src/liquidity/format.ts deleted file mode 100644 index c0f0fa2..0000000 --- a/packages/liquidity-widget/src/liquidity/format.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { formatEther } from 'viem'; - -export function formatBigIntDisplay(num: bigint): string { - if (num === 0n) return '0'; - const [whole, frac = ''] = formatEther(num).split('.'); - const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - const trimmedFrac = frac.slice(0, 2).replace(/0+$/, ''); - return trimmedFrac ? `${grouped}.${trimmedFrac}` : grouped; -} - -export function formatAmount(num: number): string { - if (num === 0) return '0'; - return num.toFixed(6).replace(/\.?0+$/, ''); -} diff --git a/packages/liquidity-widget/src/liquidity/tx-steps.ts b/packages/liquidity-widget/src/liquidity/tx-steps.ts index 0e7d480..5a962fe 100644 --- a/packages/liquidity-widget/src/liquidity/tx-steps.ts +++ b/packages/liquidity-widget/src/liquidity/tx-steps.ts @@ -25,3 +25,13 @@ export function buildTxSteps(params: { return { steps, needGdApproval, needUsdgloApproval }; } + +export function updateStep( + steps: TxStepInfo[], + index: number, + patch: Partial, +): TxStepInfo[] { + const next = steps.slice(); + next[index] = { ...next[index], ...patch }; + return next; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1451cd1..52926d1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,8 @@ { "path": "./packages/engagement-sdk" }, { "path": "./packages/savings-sdk" }, { "path": "./packages/savings-widget" }, + { "path": "./packages/liquidity-sdk" }, + { "path": "./packages/liquidity-widget" }, { "path": "./packages/good-reserve" }, { "path": "./apps/demo-identity-app" }, { "path": "./apps/engagement-app" }, From 9504e7c36905a6228e17e3281ab4dd1403eeca8e Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Thu, 23 Apr 2026 21:21:12 +0300 Subject: [PATCH 10/11] fix: unclaimed fees --- packages/liquidity-sdk/src/viem-sdk.ts | 74 +++++++++++++++---- .../components/lw-positions-panel.ts | 11 +-- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/packages/liquidity-sdk/src/viem-sdk.ts b/packages/liquidity-sdk/src/viem-sdk.ts index 64880fb..59f3349 100644 --- a/packages/liquidity-sdk/src/viem-sdk.ts +++ b/packages/liquidity-sdk/src/viem-sdk.ts @@ -147,7 +147,18 @@ export class GooddollarLiquiditySDK { })), }); - const positions: PositionData[] = []; + type ParsedPosition = { + tokenId: bigint; + token0: string; + token1: string; + fee: number; + tickLower: number; + tickUpper: number; + liquidity: bigint; + tokensOwed0: bigint; + tokensOwed1: bigint; + }; + const parsed: ParsedPosition[] = []; for (let i = 0; i < tokenIds.length; i++) { const res = positionResults[i]; if (res.status !== 'success') continue; @@ -166,22 +177,59 @@ export class GooddollarLiquiditySDK { if (!matchesPool) continue; if (liquidity === 0n && tokensOwed0 === 0n && tokensOwed1 === 0n) continue; - const { amount0, amount1 } = getAmountsForPositionApprox( - liquidity, tickLower, tickUpper, currentTick, - ); - - positions.push({ + parsed.push({ tokenId: tokenIds[i], - token0, token1, - fee, tickLower, tickUpper, - liquidity, - tokensOwed0, tokensOwed1, - amount0, amount1, - inRange: currentTick >= tickLower && currentTick < tickUpper, + token0, token1, fee, tickLower, tickUpper, + liquidity, tokensOwed0, tokensOwed1, }); } - return positions; + console.log('Parsed positions:', parsed); + + if (parsed.length === 0) return []; + + const feeSimResults = await Promise.all( + parsed.map((p) => + this.publicClient.simulateContract({ + account: userAddress, + address: POSITION_MANAGER, + abi: POSITION_MANAGER_ABI, + functionName: 'collect', + args: [{ + tokenId: p.tokenId, + recipient: userAddress, + amount0Max: MAX_UINT128, + amount1Max: MAX_UINT128, + }], + }).then( + (r) => { + console.log(r.result); + return r.result as readonly [bigint, bigint] + }, + () => [p.tokensOwed0, p.tokensOwed1] as const, + ), + ), + ); + + return parsed.map((p, i) => { + const [simOwed0, simOwed1] = feeSimResults[i]; + const { amount0, amount1 } = getAmountsForPositionApprox( + p.liquidity, p.tickLower, p.tickUpper, currentTick, + ); + return { + tokenId: p.tokenId, + token0: p.token0, + token1: p.token1, + fee: p.fee, + tickLower: p.tickLower, + tickUpper: p.tickUpper, + liquidity: p.liquidity, + tokensOwed0: simOwed0, + tokensOwed1: simOwed1, + amount0, amount1, + inRange: currentTick >= p.tickLower && currentTick < p.tickUpper, + }; + }); } // ── Writes ─────────────────────────────────────────────────────────── diff --git a/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts b/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts index b930e70..4597204 100644 --- a/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts +++ b/packages/liquidity-widget/src/liquidity/components/lw-positions-panel.ts @@ -83,7 +83,8 @@ export class LwPositionsPanel extends LitElement { private _fmt(val: bigint): string { const n = Number(formatEther(val)); if (n === 0) return '0'; - return Intl.NumberFormat(undefined, { maximumFractionDigits: 4 }).format(n); + const frac = n < 10 ? 4 : n < 100 ? 2 : 1; + return Intl.NumberFormat(undefined, { maximumFractionDigits: frac }).format(n); } render() { @@ -122,12 +123,8 @@ export class LwPositionsPanel extends LitElement { ${this._fmt(totalUsdglo)}
- Unclaimed G$ Fees - ${this._fmt(totalGdFees)} -
-
- Unclaimed USDGLO Fees - ${this._fmt(totalUsdgloFees)} + Unclaimed Fees + ${this._fmt(totalGdFees)} G$ / ${this._fmt(totalUsdgloFees)} GLO
From 67aa172819125b7f9689d2fec1401d2d0d22703e Mon Sep 17 00:00:00 2001 From: Kadir Ay Date: Mon, 15 Jun 2026 19:10:59 +0300 Subject: [PATCH 11/11] chore: iife bundle file added for liquidity-widget --- .../gooddollar-liquidity-widget.global.js | 1034 +++++++++++++++++ 1 file changed, 1034 insertions(+) create mode 100644 packages/liquidity-widget/iife/gooddollar-liquidity-widget.global.js diff --git a/packages/liquidity-widget/iife/gooddollar-liquidity-widget.global.js b/packages/liquidity-widget/iife/gooddollar-liquidity-widget.global.js new file mode 100644 index 0000000..4347b89 --- /dev/null +++ b/packages/liquidity-widget/iife/gooddollar-liquidity-widget.global.js @@ -0,0 +1,1034 @@ +"use strict";var GooddollarLiquidityWidget=(()=>{var Xi=Object.defineProperty;var jl=Object.getOwnPropertyDescriptor;var vb=Object.getOwnPropertyNames;var Eb=Object.prototype.hasOwnProperty;var E=(e,t)=>()=>(e&&(t=e(e=0)),t);var Ip=(e,t)=>{for(var r in t)Xi(e,r,{get:t[r],enumerable:!0})},Ab=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of vb(t))!Eb.call(e,o)&&o!==r&&Xi(e,o,{get:()=>t[o],enumerable:!(n=jl(t,o))||n.enumerable});return e};var Tb=e=>Ab(Xi({},"__esModule",{value:!0}),e),H=(e,t,r,n)=>{for(var o=n>1?void 0:n?jl(t,r):t,s=e.length-1,i;s>=0;s--)(i=e[s])&&(o=(n?i(t,r,o):i(o))||o);return n&&o&&Xi(t,r,o),o};var id,ad=E(()=>{"use strict";id="1.0.8"});var ke,so=E(()=>{"use strict";ad();ke=class e extends Error{constructor(t,r={}){let n=r.cause instanceof e?r.cause.details:r.cause?.message?r.cause.message:r.details,o=r.cause instanceof e&&r.cause.docsPath||r.docsPath,s=[t||"An error occurred.","",...r.metaMessages?[...r.metaMessages,""]:[],...o?[`Docs: https://abitype.dev${o}`]:[],...n?[`Details: ${n}`]:[],`Version: abitype@${id}`].join(` +`);super(s),Object.defineProperty(this,"details",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"docsPath",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"metaMessages",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"shortMessage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"AbiTypeError"}),r.cause&&(this.cause=r.cause),this.details=n,this.docsPath=o,this.metaMessages=r.metaMessages,this.shortMessage=t}}});function mt(e,t){return e.exec(t)?.groups}var zp,Lp,oa,js=E(()=>{"use strict";zp=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,Lp=/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/,oa=/^\(.+?\).*?$/});function sa(e){let t=e.type;if(cd.test(e.type)&&"components"in e){t="(";let r=e.components.length;for(let o=0;o{"use strict";js();cd=/^tuple(?(\[(\d*)\])*)$/});function io(e){let t="",r=e.length;for(let n=0;n{"use strict";ud()});function vn(e){return e.type==="function"?`function ${e.name}(${io(e.inputs)})${e.stateMutability&&e.stateMutability!=="nonpayable"?` ${e.stateMutability}`:""}${e.outputs?.length?` returns (${io(e.outputs)})`:""}`:e.type==="event"?`event ${e.name}(${io(e.inputs)})`:e.type==="error"?`error ${e.name}(${io(e.inputs)})`:e.type==="constructor"?`constructor(${io(e.inputs)})${e.stateMutability==="payable"?" payable":""}`:e.type==="fallback"?`fallback() external${e.stateMutability==="payable"?" payable":""}`:"receive() external payable"}var fd=E(()=>{"use strict";pd()});function dd(e){return ld.test(e)}function md(e){return mt(ld,e)}function yd(e){return hd.test(e)}function xd(e){return mt(hd,e)}function gd(e){return bd.test(e)}function wd(e){return mt(bd,e)}function ao(e){return vd.test(e)}function Ed(e){return mt(vd,e)}function Td(e){return Ad.test(e)}function Sd(e){return mt(Ad,e)}function Pd(e){return Id.test(e)}function Cd(e){return mt(Id,e)}function kd(e){return Lb.test(e)}var ld,hd,bd,vd,Ad,Id,Lb,_d,ia,qs=E(()=>{"use strict";js();ld=/^error (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;hd=/^event (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;bd=/^function (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)(?: (?external|public{1}))?(?: (?pure|view|nonpayable|payable{1}))?(?: returns\s?\((?.*?)\))?$/;vd=/^struct (?[a-zA-Z$_][a-zA-Z0-9$_]*) \{(?.*?)\}$/;Ad=/^constructor\((?.*?)\)(?:\s(?payable{1}))?$/;Id=/^fallback\(\) external(?:\s(?payable{1}))?$/;Lb=/^receive\(\) external payable$/;_d=new Set(["indexed"]),ia=new Set(["calldata","memory","storage"])});var aa,ca,ua,pa=E(()=>{"use strict";so();aa=class extends ke{constructor({signature:t}){super("Failed to parse ABI item.",{details:`parseAbiItem(${JSON.stringify(t,null,2)})`,docsPath:"/api/human#parseabiitem-1"}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidAbiItemError"})}},ca=class extends ke{constructor({type:t}){super("Unknown type.",{metaMessages:[`Type "${t}" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"UnknownTypeError"})}},ua=class extends ke{constructor({type:t}){super("Unknown type.",{metaMessages:[`Type "${t}" is not a valid ABI type.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"UnknownSolidityTypeError"})}}});var fa,la,da,ma,ha,Dp=E(()=>{"use strict";so();fa=class extends ke{constructor({param:t}){super("Invalid ABI parameter.",{details:t}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidParameterError"})}},la=class extends ke{constructor({param:t,name:r}){super("Invalid ABI parameter.",{details:t,metaMessages:[`"${r}" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"SolidityProtectedKeywordError"})}},da=class extends ke{constructor({param:t,type:r,modifier:n}){super("Invalid ABI parameter.",{details:t,metaMessages:[`Modifier "${n}" not allowed${r?` in "${r}" type`:""}.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidModifierError"})}},ma=class extends ke{constructor({param:t,type:r,modifier:n}){super("Invalid ABI parameter.",{details:t,metaMessages:[`Modifier "${n}" not allowed${r?` in "${r}" type`:""}.`,`Data location can only be specified for array, struct, or mapping types, but "${n}" was given.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidFunctionModifierError"})}},ha=class extends ke{constructor({abiParameter:t}){super("Invalid ABI parameter.",{details:JSON.stringify(t,null,2),metaMessages:["ABI parameter type is invalid."]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidAbiTypeParameterError"})}}});var Gt,ya,xa,Hp=E(()=>{"use strict";so();Gt=class extends ke{constructor({signature:t,type:r}){super(`Invalid ${r} signature.`,{details:t}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidSignatureError"})}},ya=class extends ke{constructor({signature:t}){super("Unknown signature.",{details:t}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"UnknownSignatureError"})}},xa=class extends ke{constructor({signature:t}){super("Invalid struct signature.",{details:t,metaMessages:["No properties exist."]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidStructSignatureError"})}}});var ba,Bd=E(()=>{"use strict";so();ba=class extends ke{constructor({type:t}){super("Circular reference detected.",{metaMessages:[`Struct "${t}" is a circular reference.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"CircularReferenceError"})}}});var ga,Rd=E(()=>{"use strict";so();ga=class extends ke{constructor({current:t,depth:r}){super("Unbalanced parentheses.",{metaMessages:[`"${t.trim()}" has too many ${r>0?"opening":"closing"} parentheses.`],details:`Depth "${r}"`}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidParenthesisError"})}}});function $d(e,t,r){let n="";if(r)for(let o of Object.entries(r)){if(!o)continue;let s="";for(let i of o[1])s+=`[${i.type}${i.name?`:${i.name}`:""}]`;n+=`(${o[0]}{${s}})`}return t?`${t}:${e}${n}`:e}var wa,Nd=E(()=>{"use strict";wa=new Map([["address",{type:"address"}],["bool",{type:"bool"}],["bytes",{type:"bytes"}],["bytes32",{type:"bytes32"}],["int",{type:"int256"}],["int256",{type:"int256"}],["string",{type:"string"}],["uint",{type:"uint256"}],["uint8",{type:"uint8"}],["uint16",{type:"uint16"}],["uint24",{type:"uint24"}],["uint32",{type:"uint32"}],["uint64",{type:"uint64"}],["uint96",{type:"uint96"}],["uint112",{type:"uint112"}],["uint160",{type:"uint160"}],["uint192",{type:"uint192"}],["uint256",{type:"uint256"}],["address owner",{type:"address",name:"owner"}],["address to",{type:"address",name:"to"}],["bool approved",{type:"bool",name:"approved"}],["bytes _data",{type:"bytes",name:"_data"}],["bytes data",{type:"bytes",name:"data"}],["bytes signature",{type:"bytes",name:"signature"}],["bytes32 hash",{type:"bytes32",name:"hash"}],["bytes32 r",{type:"bytes32",name:"r"}],["bytes32 root",{type:"bytes32",name:"root"}],["bytes32 s",{type:"bytes32",name:"s"}],["string name",{type:"string",name:"name"}],["string symbol",{type:"string",name:"symbol"}],["string tokenURI",{type:"string",name:"tokenURI"}],["uint tokenId",{type:"uint256",name:"tokenId"}],["uint8 v",{type:"uint8",name:"v"}],["uint256 balance",{type:"uint256",name:"balance"}],["uint256 tokenId",{type:"uint256",name:"tokenId"}],["uint256 value",{type:"uint256",name:"value"}],["event:address indexed from",{type:"address",name:"from",indexed:!0}],["event:address indexed to",{type:"address",name:"to",indexed:!0}],["event:uint indexed tokenId",{type:"uint256",name:"tokenId",indexed:!0}],["event:uint256 indexed tokenId",{type:"uint256",name:"tokenId",indexed:!0}]])});function Gs(e,t={}){if(gd(e))return Db(e,t);if(yd(e))return Hb(e,t);if(dd(e))return jb(e,t);if(Td(e))return qb(e,t);if(Pd(e))return Gb(e);if(kd(e))return{type:"receive",stateMutability:"payable"};throw new ya({signature:e})}function Db(e,t={}){let r=wd(e);if(!r)throw new Gt({signature:e,type:"function"});let n=Bt(r.parameters),o=[],s=n.length;for(let a=0;a{"use strict";js();pa();Dp();Hp();Rd();Nd();qs();Vb=/^(?[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,Wb=/^\((?.+?)\)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,Kb=/^u?int$/;Yb=/^(?:after|alias|anonymous|apply|auto|byte|calldata|case|catch|constant|copyof|default|defined|error|event|external|false|final|function|immutable|implements|in|indexed|inline|internal|let|mapping|match|memory|mutable|null|of|override|partial|private|promise|public|pure|reference|relocatable|return|returns|sizeof|static|storage|struct|super|supports|switch|this|true|try|typedef|typeof|var|view|virtual)$/});function Ea(e){let t={},r=e.length;for(let i=0;i{"use strict";js();pa();Dp();Hp();Bd();qs();va();Jb=/^(?[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?$/});function Aa(e){let t=Ea(e),r=[],n=e.length;for(let o=0;o{"use strict";qs();qp();va()});function Ta(e){let t;if(typeof e=="string")t=Gs(e);else{let r=Ea(e),n=e.length;for(let o=0;o{"use strict";pa();qs();qp();va()});var Sa=E(()=>{"use strict";fd();Od();Ud()});function Re(e,{includeName:t=!1}={}){if(e.type!=="function"&&e.type!=="event"&&e.type!=="error")throw new Ia(e.type);return`${e.name}(${Vs(e.inputs,{includeName:t})})`}function Vs(e,{includeName:t=!1}={}){return e?e.map(r=>eg(r,{includeName:t})).join(t?", ":","):""}function eg(e,{includeName:t}){return e.type.startsWith("tuple")?`(${Vs(e.components,{includeName:t})})${e.type.slice(5)}`:e.type+(t&&e.name?` ${e.name}`:"")}var ur=E(()=>{"use strict";Ae()});function Ie(e,{strict:t=!0}={}){return!e||typeof e!="string"?!1:t?/^0x[0-9a-fA-F]*$/.test(e):e.startsWith("0x")}var Rt=E(()=>{"use strict"});function ne(e){return Ie(e,{strict:!1})?Math.ceil((e.length-2)/2):e.length}var wt=E(()=>{"use strict";Rt()});var Gp,Md=E(()=>{"use strict";Gp="2.28.4"});function zd(e,t){return t?.(e)?e:e&&typeof e=="object"&&"cause"in e&&e.cause!==void 0?zd(e.cause,t):t?null:e}var Vp,g,Y=E(()=>{"use strict";Md();Vp={getDocsUrl:({docsBaseUrl:e,docsPath:t="",docsSlug:r})=>t?`${e??"https://viem.sh"}${t}${r?`#${r}`:""}`:void 0,version:`viem@${Gp}`},g=class e extends Error{constructor(t,r={}){let n=r.cause instanceof e?r.cause.details:r.cause?.message?r.cause.message:r.details,o=r.cause instanceof e&&r.cause.docsPath||r.docsPath,s=Vp.getDocsUrl?.({...r,docsPath:o}),i=[t||"An error occurred.","",...r.metaMessages?[...r.metaMessages,""]:[],...s?[`Docs: ${s}`]:[],...n?[`Details: ${n}`]:[],...Vp.version?[`Version: ${Vp.version}`]:[]].join(` +`);super(i,r.cause?{cause:r.cause}:void 0),Object.defineProperty(this,"details",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"docsPath",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"metaMessages",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"shortMessage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"BaseError"}),this.details=n,this.docsPath=o,this.metaMessages=r.metaMessages,this.name=r.name??this.name,this.shortMessage=t,this.version=Gp}walk(t){return zd(this,t)}}});var Pa,Ws,co,vt,Ca,ka,_a,Ba,Ks,uo,Ra,po,Ys,$t,fo,$a,Na,Fa,Nt,Vt,Oa,Ua,lo,Ia,Ae=E(()=>{"use strict";ur();wt();Y();Pa=class extends g{constructor({docsPath:t}){super(["A constructor was not found on the ABI.","Make sure you are using the correct ABI and that the constructor exists on it."].join(` +`),{docsPath:t,name:"AbiConstructorNotFoundError"})}},Ws=class extends g{constructor({docsPath:t}){super(["Constructor arguments were provided (`args`), but a constructor parameters (`inputs`) were not found on the ABI.","Make sure you are using the correct ABI, and that the `inputs` attribute on the constructor exists."].join(` +`),{docsPath:t,name:"AbiConstructorParamsNotFoundError"})}},co=class extends g{constructor({data:t,params:r,size:n}){super([`Data size of ${n} bytes is too small for given parameters.`].join(` +`),{metaMessages:[`Params: (${Vs(r,{includeName:!0})})`,`Data: ${t} (${n} bytes)`],name:"AbiDecodingDataSizeTooSmallError"}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"params",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"size",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=t,this.params=r,this.size=n}},vt=class extends g{constructor(){super('Cannot decode zero data ("0x") with ABI parameters.',{name:"AbiDecodingZeroDataError"})}},Ca=class extends g{constructor({expectedLength:t,givenLength:r,type:n}){super([`ABI encoding array length mismatch for type ${n}.`,`Expected length: ${t}`,`Given length: ${r}`].join(` +`),{name:"AbiEncodingArrayLengthMismatchError"})}},ka=class extends g{constructor({expectedSize:t,value:r}){super(`Size of bytes "${r}" (bytes${ne(r)}) does not match expected size (bytes${t}).`,{name:"AbiEncodingBytesSizeMismatchError"})}},_a=class extends g{constructor({expectedLength:t,givenLength:r}){super(["ABI encoding params/values length mismatch.",`Expected length (params): ${t}`,`Given length (values): ${r}`].join(` +`),{name:"AbiEncodingLengthMismatchError"})}},Ba=class extends g{constructor(t,{docsPath:r}){super([`Arguments (\`args\`) were provided to "${t}", but "${t}" on the ABI does not contain any parameters (\`inputs\`).`,"Cannot encode error result without knowing what the parameter types are.","Make sure you are using the correct ABI and that the inputs exist on it."].join(` +`),{docsPath:r,name:"AbiErrorInputsNotFoundError"})}},Ks=class extends g{constructor(t,{docsPath:r}={}){super([`Error ${t?`"${t}" `:""}not found on ABI.`,"Make sure you are using the correct ABI and that the error exists on it."].join(` +`),{docsPath:r,name:"AbiErrorNotFoundError"})}},uo=class extends g{constructor(t,{docsPath:r}){super([`Encoded error signature "${t}" not found on ABI.`,"Make sure you are using the correct ABI and that the error exists on it.",`You can look up the decoded signature here: https://openchain.xyz/signatures?query=${t}.`].join(` +`),{docsPath:r,name:"AbiErrorSignatureNotFoundError"}),Object.defineProperty(this,"signature",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.signature=t}},Ra=class extends g{constructor({docsPath:t}){super("Cannot extract event signature from empty topics.",{docsPath:t,name:"AbiEventSignatureEmptyTopicsError"})}},po=class extends g{constructor(t,{docsPath:r}){super([`Encoded event signature "${t}" not found on ABI.`,"Make sure you are using the correct ABI and that the event exists on it.",`You can look up the signature here: https://openchain.xyz/signatures?query=${t}.`].join(` +`),{docsPath:r,name:"AbiEventSignatureNotFoundError"})}},Ys=class extends g{constructor(t,{docsPath:r}={}){super([`Event ${t?`"${t}" `:""}not found on ABI.`,"Make sure you are using the correct ABI and that the event exists on it."].join(` +`),{docsPath:r,name:"AbiEventNotFoundError"})}},$t=class extends g{constructor(t,{docsPath:r}={}){super([`Function ${t?`"${t}" `:""}not found on ABI.`,"Make sure you are using the correct ABI and that the function exists on it."].join(` +`),{docsPath:r,name:"AbiFunctionNotFoundError"})}},fo=class extends g{constructor(t,{docsPath:r}){super([`Function "${t}" does not contain any \`outputs\` on ABI.`,"Cannot decode function result without knowing what the parameter types are.","Make sure you are using the correct ABI and that the function exists on it."].join(` +`),{docsPath:r,name:"AbiFunctionOutputsNotFoundError"})}},$a=class extends g{constructor(t,{docsPath:r}){super([`Encoded function signature "${t}" not found on ABI.`,"Make sure you are using the correct ABI and that the function exists on it.",`You can look up the signature here: https://openchain.xyz/signatures?query=${t}.`].join(` +`),{docsPath:r,name:"AbiFunctionSignatureNotFoundError"})}},Na=class extends g{constructor(t,r){super("Found ambiguous types in overloaded ABI items.",{metaMessages:[`\`${t.type}\` in \`${Re(t.abiItem)}\`, and`,`\`${r.type}\` in \`${Re(r.abiItem)}\``,"","These types encode differently and cannot be distinguished at runtime.","Remove one of the ambiguous items in the ABI."],name:"AbiItemAmbiguityError"})}},Fa=class extends g{constructor({expectedSize:t,givenSize:r}){super(`Expected bytes${t}, got bytes${r}.`,{name:"BytesSizeMismatchError"})}},Nt=class extends g{constructor({abiItem:t,data:r,params:n,size:o}){super([`Data size of ${o} bytes is too small for non-indexed event parameters.`].join(` +`),{metaMessages:[`Params: (${Vs(n,{includeName:!0})})`,`Data: ${r} (${o} bytes)`],name:"DecodeLogDataMismatch"}),Object.defineProperty(this,"abiItem",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"params",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"size",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiItem=t,this.data=r,this.params=n,this.size=o}},Vt=class extends g{constructor({abiItem:t,param:r}){super([`Expected a topic for indexed event parameter${r.name?` "${r.name}"`:""} on event "${Re(t,{includeName:!0})}".`].join(` +`),{name:"DecodeLogTopicsMismatch"}),Object.defineProperty(this,"abiItem",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiItem=t}},Oa=class extends g{constructor(t,{docsPath:r}){super([`Type "${t}" is not a valid encoding type.`,"Please provide a valid ABI type."].join(` +`),{docsPath:r,name:"InvalidAbiEncodingType"})}},Ua=class extends g{constructor(t,{docsPath:r}){super([`Type "${t}" is not a valid decoding type.`,"Please provide a valid ABI type."].join(` +`),{docsPath:r,name:"InvalidAbiDecodingType"})}},lo=class extends g{constructor(t){super([`Value "${t}" is not a valid array.`].join(` +`),{name:"InvalidArrayError"})}},Ia=class extends g{constructor(t){super([`"${t}" is not a valid definition type.`,'Valid types: "function", "event", "error"'].join(` +`),{name:"InvalidDefinitionTypeError"})}}});var Zs,Xs,Js,za=E(()=>{"use strict";Y();Zs=class extends g{constructor({offset:t,position:r,size:n}){super(`Slice ${r==="start"?"starting":"ending"} at offset "${t}" is out-of-bounds (size: ${n}).`,{name:"SliceOffsetOutOfBoundsError"})}},Xs=class extends g{constructor({size:t,targetSize:r,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (${t}) exceeds padding size (${r}).`,{name:"SizeExceedsPaddingSizeError"})}},Js=class extends g{constructor({size:t,targetSize:r,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} is expected to be ${r} ${n} long, but is ${t} ${n} long.`,{name:"InvalidBytesLengthError"})}}});function Br(e,{dir:t,size:r=32}={}){return typeof e=="string"?pr(e,{dir:t,size:r}):tg(e,{dir:t,size:r})}function pr(e,{dir:t,size:r=32}={}){if(r===null)return e;let n=e.replace("0x","");if(n.length>r*2)throw new Xs({size:Math.ceil(n.length/2),targetSize:r,type:"hex"});return`0x${n[t==="right"?"padEnd":"padStart"](r*2,"0")}`}function tg(e,{dir:t,size:r=32}={}){if(r===null)return e;if(e.length>r)throw new Xs({size:e.length,targetSize:r,type:"bytes"});let n=new Uint8Array(r);for(let o=0;o{"use strict";za()});var mo,Da,Ha,ja,Qs=E(()=>{"use strict";Y();mo=class extends g{constructor({max:t,min:r,signed:n,size:o,value:s}){super(`Number "${s}" is not in safe ${o?`${o*8}-bit ${n?"signed":"unsigned"} `:""}integer range ${t?`(${r} to ${t})`:`(above ${r})`}`,{name:"IntegerOutOfRangeError"})}},Da=class extends g{constructor(t){super(`Bytes value "${t}" is not a valid boolean. The bytes array must contain a single byte of either a 0 or 1 value.`,{name:"InvalidBytesBooleanError"})}},Ha=class extends g{constructor(t){super(`Hex value "${t}" is not a valid boolean. The hex value must be "0x0" (false) or "0x1" (true).`,{name:"InvalidHexBooleanError"})}},ja=class extends g{constructor({givenSize:t,maxSize:r}){super(`Size cannot exceed ${r} bytes. Given size: ${t} bytes.`,{name:"SizeOverflowError"})}}});function $e(e,{dir:t="left"}={}){let r=typeof e=="string"?e.replace("0x",""):e,n=0;for(let o=0;o{"use strict"});function it(e,{size:t}){if(ne(e)>t)throw new ja({givenSize:ne(e),maxSize:t})}function ge(e,t={}){let{signed:r}=t;t.size&&it(e,{size:t.size});let n=BigInt(e);if(!r)return n;let o=(e.length-2)/2,s=(1n<{"use strict";Qs();wt();En()});function M(e,t={}){return typeof e=="number"||typeof e=="bigint"?R(e,t):typeof e=="string"?Wt(e,t):typeof e=="boolean"?Kp(e,t):se(e,t)}function Kp(e,t={}){let r=`0x${Number(e)}`;return typeof t.size=="number"?(it(r,{size:t.size}),Br(r,{size:t.size})):r}function se(e,t={}){let r="";for(let o=0;os||o{"use strict";Qs();La();Ve();rg=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));ng=new TextEncoder});function Et(e,t={}){return typeof e=="number"||typeof e=="bigint"?ig(e,t):typeof e=="boolean"?sg(e,t):Ie(e)?Ne(e,t):Ft(e,t)}function sg(e,t={}){let r=new Uint8Array(1);return r[0]=Number(e),typeof t.size=="number"?(it(r,{size:t.size}),Br(r,{size:t.size})):r}function Ld(e){if(e>=fr.zero&&e<=fr.nine)return e-fr.zero;if(e>=fr.A&&e<=fr.F)return e-(fr.A-10);if(e>=fr.a&&e<=fr.f)return e-(fr.a-10)}function Ne(e,t={}){let r=e;t.size&&(it(r,{size:t.size}),r=Br(r,{dir:"right",size:t.size}));let n=r.slice(2);n.length%2&&(n=`0${n}`);let o=n.length/2,s=new Uint8Array(o);for(let i=0,a=0;i{"use strict";Y();Rt();La();Ve();V();og=new TextEncoder;fr={zero:48,nine:57,A:65,F:70,a:97,f:102}});function ei(e){if(!Number.isSafeInteger(e)||e<0)throw new Error("positive integer expected, got "+e)}function ag(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Rr(e,...t){if(!ag(e))throw new Error("Uint8Array expected");if(t.length>0&&!t.includes(e.length))throw new Error("Uint8Array expected of length "+t+", got length="+e.length)}function Dd(e){if(typeof e!="function"||typeof e.create!="function")throw new Error("Hash should be wrapped by utils.wrapConstructor");ei(e.outputLen),ei(e.blockLen)}function lr(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function qa(e,t){Rr(e);let r=t.outputLen;if(e.length{"use strict"});function cg(e,t=!1){return t?{h:Number(e&Ga),l:Number(e>>Hd&Ga)}:{h:Number(e>>Hd&Ga)|0,l:Number(e&Ga)|0}}function jd(e,t=!1){let r=new Uint32Array(e.length),n=new Uint32Array(e.length);for(let o=0;o{"use strict";Ga=BigInt(4294967295),Hd=BigInt(32);qd=(e,t,r)=>e<>>32-r,Gd=(e,t,r)=>t<>>32-r,Vd=(e,t,r)=>t<>>64-r,Wd=(e,t,r)=>e<>>64-r});var An,Yd=E(()=>{"use strict";An=typeof globalThis=="object"&&"crypto"in globalThis?globalThis.crypto:void 0});function Zd(e){return new Uint32Array(e.buffer,e.byteOffset,Math.floor(e.byteLength/4))}function Va(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function Ot(e,t){return e<<32-t|e>>>t}function ug(e){return e<<24&4278190080|e<<8&16711680|e>>>8&65280|e>>>24&255}function Zp(e){for(let t=0;te().update(Nr(n)).digest(),r=e();return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.create=()=>e(),t}function Jd(e){let t=(n,o)=>e(o).update(Nr(n)).digest(),r=e({});return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.create=n=>e(n),t}function Ka(e=32){if(An&&typeof An.getRandomValues=="function")return An.getRandomValues(new Uint8Array(e));if(An&&typeof An.randomBytes=="function")return Uint8Array.from(An.randomBytes(e));throw new Error("crypto.getRandomValues must be defined")}var Yp,_T,$r,Tn=E(()=>{"use strict";Yd();ti();Yp=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;_T=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function";$r=class{clone(){return this._cloneInto()}}});function bg(e,t=24){let r=new Uint32Array(10);for(let n=24-t;n<24;n++){for(let i=0;i<10;i++)r[i]=e[i]^e[i+10]^e[i+20]^e[i+30]^e[i+40];for(let i=0;i<10;i+=2){let a=(i+8)%10,c=(i+2)%10,u=r[c],f=r[c+1],p=Qd(u,f,1)^r[a],l=em(u,f,1)^r[a+1];for(let d=0;d<50;d+=10)e[i+d]^=p,e[i+d+1]^=l}let o=e[2],s=e[3];for(let i=0;i<24;i++){let a=rm[i],c=Qd(o,s,a),u=em(o,s,a),f=tm[i];o=e[f],s=e[f+1],e[f]=c,e[f+1]=u}for(let i=0;i<50;i+=10){for(let a=0;a<10;a++)r[a]=e[i+a];for(let a=0;a<10;a++)e[i+a]^=~r[(a+2)%10]&r[(a+4)%10]}e[0]^=yg[n],e[1]^=xg[n]}r.fill(0)}var tm,rm,nm,fg,ri,lg,dg,mg,hg,yg,xg,Qd,em,Ya,Fr,FT,OT,UT,MT,zT,om,LT,DT,sm,HT,jT,im=E(()=>{"use strict";ti();Kd();Tn();tm=[],rm=[],nm=[],fg=BigInt(0),ri=BigInt(1),lg=BigInt(2),dg=BigInt(7),mg=BigInt(256),hg=BigInt(113);for(let e=0,t=ri,r=1,n=0;e<24;e++){[r,n]=[n,(2*r+3*n)%5],tm.push(2*(5*n+r)),rm.push((e+1)*(e+2)/2%64);let o=fg;for(let s=0;s<7;s++)t=(t<>dg)*hg)%mg,t&lg&&(o^=ri<<(ri<r>32?Vd(e,t,r):qd(e,t,r),em=(e,t,r)=>r>32?Wd(e,t,r):Gd(e,t,r);Ya=class e extends $r{constructor(t,r,n,o=!1,s=24){if(super(),this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,this.enableXOF=!1,this.blockLen=t,this.suffix=r,this.outputLen=n,this.enableXOF=o,this.rounds=s,ei(n),0>=this.blockLen||this.blockLen>=200)throw new Error("Sha3 supports only keccak-f1600 function");this.state=new Uint8Array(200),this.state32=Zd(this.state)}keccak(){Yp||Zp(this.state32),bg(this.state32,this.rounds),Yp||Zp(this.state32),this.posOut=0,this.pos=0}update(t){lr(this);let{blockLen:r,state:n}=this;t=Nr(t);let o=t.length;for(let s=0;s=n&&this.keccak();let i=Math.min(n-this.posOut,s-o);t.set(r.subarray(this.posOut,this.posOut+i),o),this.posOut+=i,o+=i}return t}xofInto(t){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(t)}xof(t){return ei(t),this.xofInto(new Uint8Array(t))}digestInto(t){if(qa(t,this),this.finished)throw new Error("digest() was already called");return this.writeInto(t),this.destroy(),t}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,this.state.fill(0)}_cloneInto(t){let{blockLen:r,suffix:n,outputLen:o,rounds:s,enableXOF:i}=this;return t||(t=new e(r,n,o,i,s)),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=s,t.suffix=n,t.outputLen=o,t.enableXOF=i,t.destroyed=this.destroyed,t}},Fr=(e,t,r)=>Wa(()=>new Ya(t,e,r)),FT=Fr(6,144,224/8),OT=Fr(6,136,256/8),UT=Fr(6,104,384/8),MT=Fr(6,72,512/8),zT=Fr(1,144,224/8),om=Fr(1,136,256/8),LT=Fr(1,104,384/8),DT=Fr(1,72,512/8),sm=(e,t,r)=>Jd((n={})=>new Ya(t,e,n.dkLen===void 0?r:n.dkLen,!0)),HT=sm(31,168,128/8),jT=sm(31,136,256/8)});function de(e,t){let r=t||"hex",n=om(Ie(e,{strict:!1})?Et(e):e);return r==="bytes"?n:M(n)}var Ut=E(()=>{"use strict";im();Rt();He();V()});function am(e){return gg(e)}var gg,cm=E(()=>{"use strict";He();Ut();gg=e=>de(Et(e))});function um(e){let t=!0,r="",n=0,o="",s=!1;for(let i=0;i{"use strict";Y()});var fm,lm=E(()=>{"use strict";Sa();pm();fm=e=>{let t=typeof e=="string"?e:vn(e);return um(t)}});function Za(e){return am(fm(e))}var Xp=E(()=>{"use strict";cm();lm()});var Or,ni=E(()=>{"use strict";Xp();Or=Za});var fe,Mt=E(()=>{"use strict";Y();fe=class extends g{constructor({address:t}){super(`Address "${t}" is invalid.`,{metaMessages:["- Address must be a hex value of 20 bytes (40 hex characters).","- Address must match its checksum counterpart."],name:"InvalidAddressError"})}}});var Kt,oi=E(()=>{"use strict";Kt=class extends Map{constructor(t){super(),Object.defineProperty(this,"maxSize",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.maxSize=t}get(t){let r=super.get(t);return super.has(t)&&r!==void 0&&(this.delete(t),super.set(t,r)),r}set(t,r){if(super.set(t,r),this.maxSize&&this.size>this.maxSize){let n=this.keys().next().value;n&&this.delete(n)}return this}}});function dr(e,t){if(Jp.has(`${e}.${t}`))return Jp.get(`${e}.${t}`);let r=t?`${t}${e.toLowerCase()}`:e.substring(2).toLowerCase(),n=de(Ft(r),"bytes"),o=(t?r.substring(`${t}0x`.length):r).split("");for(let i=0;i<40;i+=2)n[i>>1]>>4>=8&&o[i]&&(o[i]=o[i].toUpperCase()),(n[i>>1]&15)>=8&&o[i+1]&&(o[i+1]=o[i+1].toUpperCase());let s=`0x${o.join("")}`;return Jp.set(`${e}.${t}`,s),s}function Xa(e,t){if(!ie(e,{strict:!1}))throw new fe({address:e});return dr(e,t)}var Jp,Sn=E(()=>{"use strict";Mt();He();Ut();oi();At();Jp=new Kt(8192)});function ie(e,t){let{strict:r=!0}=t??{},n=`${e}.${r}`;if(Qp.has(n))return Qp.get(n);let o=wg.test(e)?e.toLowerCase()===e?!0:r?dr(e)===e:!0:!1;return Qp.set(n,o),o}var wg,Qp,At=E(()=>{"use strict";oi();Sn();wg=/^0x[a-fA-F0-9]{40}$/,Qp=new Kt(8192)});function rt(e){return typeof e[0]=="string"?_e(e):vg(e)}function vg(e){let t=0;for(let o of e)t+=o.length;let r=new Uint8Array(t),n=0;for(let o of e)r.set(o,n),n+=o.length;return r}function _e(e){return`0x${e.reduce((t,r)=>t+r.replace("0x",""),"")}`}var at=E(()=>{"use strict"});function Tt(e,t,r,{strict:n}={}){return Ie(e,{strict:!1})?tf(e,t,r,{strict:n}):ef(e,t,r,{strict:n})}function dm(e,t){if(typeof t=="number"&&t>0&&t>ne(e)-1)throw new Zs({offset:t,position:"start",size:ne(e)})}function mm(e,t,r){if(typeof t=="number"&&typeof r=="number"&&ne(e)!==r-t)throw new Zs({offset:r,position:"end",size:ne(e)})}function ef(e,t,r,{strict:n}={}){dm(e,t);let o=e.slice(t,r);return n&&mm(o,t,r),o}function tf(e,t,r,{strict:n}={}){dm(e,t);let o=`0x${e.replace("0x","").slice((t??0)*2,(r??e.length)*2)}`;return n&&mm(o,t,r),o}var Ur=E(()=>{"use strict";za();Rt();wt()});var hm,Ja,rf=E(()=>{"use strict";hm=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,Ja=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/});function We(e,t){if(e.length!==t.length)throw new _a({expectedLength:e.length,givenLength:t.length});let r=Eg({params:e,values:t}),n=of(r);return n.length===0?"0x":n}function Eg({params:e,values:t}){let r=[];for(let n=0;n0?rt([a,i]):a}}if(o)return{dynamic:!0,encoded:i}}return{dynamic:!1,encoded:rt(s.map(({encoded:i})=>i))}}function Sg(e,{param:t}){let[,r]=t.type.split("bytes"),n=ne(e);if(!r){let o=e;return n%32!==0&&(o=pr(o,{dir:"right",size:Math.ceil((e.length-2)/2/32)*32})),{dynamic:!0,encoded:rt([pr(R(n,{size:32})),o])}}if(n!==Number.parseInt(r))throw new ka({expectedSize:Number.parseInt(r),value:e});return{dynamic:!1,encoded:pr(e,{dir:"right"})}}function Ig(e){if(typeof e!="boolean")throw new g(`Invalid boolean value: "${e}" (type: ${typeof e}). Expected: \`true\` or \`false\`.`);return{dynamic:!1,encoded:pr(Kp(e))}}function Pg(e,{signed:t,size:r=256}){if(typeof r=="number"){let n=2n**(BigInt(r)-(t?1n:0n))-1n,o=t?-n-1n:0n;if(e>n||eo))}}function Qa(e){let t=e.match(/^(.*)\[(\d+)?\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}var Yt=E(()=>{"use strict";Ae();Mt();Y();Qs();At();at();La();wt();Ur();V();rf()});var Zt,ho=E(()=>{"use strict";Ur();Xp();Zt=e=>Tt(Za(e),0,4)});function ct(e){let{abi:t,args:r=[],name:n}=e,o=Ie(n,{strict:!1}),s=t.filter(a=>o?a.type==="function"?Zt(a)===n:a.type==="event"?Or(a)===n:!1:"name"in a&&a.name===n);if(s.length===0)return;if(s.length===1)return s[0];let i;for(let a of s){if(!("inputs"in a))continue;if(!r||r.length===0){if(!a.inputs||a.inputs.length===0)return a;continue}if(!a.inputs||a.inputs.length===0||a.inputs.length!==r.length)continue;if(r.every((u,f)=>{let p="inputs"in a&&a.inputs[f];return p?sf(u,p):!1})){if(i&&"inputs"in i&&i.inputs){let u=ym(a.inputs,i.inputs,r);if(u)throw new Na({abiItem:a,type:u[0]},{abiItem:i,type:u[1]})}i=a}}return i||s[0]}function sf(e,t){let r=typeof e,n=t.type;switch(n){case"address":return ie(e,{strict:!1});case"bool":return r==="boolean";case"function":return r==="string";case"string":return r==="string";default:return n==="tuple"&&"components"in t?Object.values(t.components).every((o,s)=>sf(Object.values(e)[s],o)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(n)?r==="number"||r==="bigint":/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(n)?r==="string"||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(n)?Array.isArray(e)&&e.every(o=>sf(o,{...t,type:n.replace(/(\[[0-9]{0,}\])$/,"")})):!1}}function ym(e,t,r){for(let n in e){let o=e[n],s=t[n];if(o.type==="tuple"&&s.type==="tuple"&&"components"in o&&"components"in s)return ym(o.components,s.components,r[n]);let i=[o.type,s.type];if(i.includes("address")&&i.includes("bytes20")?!0:i.includes("address")&&i.includes("string")?ie(r[n],{strict:!1}):i.includes("address")&&i.includes("bytes")?ie(r[n],{strict:!1}):!1)return i}}var Mr=E(()=>{"use strict";Ae();Rt();At();ni();ho()});function Z(e){return typeof e=="string"?{address:e,type:"json-rpc"}:e}var Pe=E(()=>{"use strict"});function wm(e){let{abi:t,args:r,functionName:n}=e,o=t[0];if(n){let s=ct({abi:t,args:r,name:n});if(!s)throw new $t(n,{docsPath:gm});o=s}if(o.type!=="function")throw new $t(void 0,{docsPath:gm});return{abi:[o],functionName:Zt(Re(o))}}var gm,vm=E(()=>{"use strict";Ae();ho();ur();Mr();gm="/docs/contract/encodeFunctionData"});function be(e){let{args:t}=e,{abi:r,functionName:n}=e.abi.length===1&&e.functionName?.startsWith("0x")?e:wm(e),o=r[0],s=n,i="inputs"in o&&o.inputs?We(o.inputs,t??[]):void 0;return _e([s,i??"0x"])}var ht=E(()=>{"use strict";at();Yt();vm()});var tc,rc,Em,si=E(()=>{"use strict";tc={1:"An `assert` condition failed.",17:"Arithmetic operation resulted in underflow or overflow.",18:"Division or modulo by zero (e.g. `5 / 0` or `23 % 0`).",33:"Attempted to convert to an invalid type.",34:"Attempted to access a storage byte array that is incorrectly encoded.",49:"Performed `.pop()` on an empty array",50:"Array index is out of bounds.",65:"Allocated too much memory or created an array which is too large.",81:"Attempted to call a zero-initialized variable of internal function type."},rc={inputs:[{name:"message",type:"string"}],name:"Error",type:"error"},Em={inputs:[{name:"reason",type:"uint256"}],name:"Panic",type:"error"}});var ii,yo,nc,af=E(()=>{"use strict";Y();ii=class extends g{constructor({offset:t}){super(`Offset \`${t}\` cannot be negative.`,{name:"NegativeOffsetError"})}},yo=class extends g{constructor({length:t,position:r}){super(`Position \`${r}\` is out of bounds (\`0 < position < ${t}\`).`,{name:"PositionOutOfBoundsError"})}},nc=class extends g{constructor({count:t,limit:r}){super(`Recursive read limit of \`${r}\` exceeded (recursive read count: \`${t}\`).`,{name:"RecursiveReadLimitExceededError"})}}});function xo(e,{recursiveReadLimit:t=8192}={}){let r=Object.create(_g);return r.bytes=e,r.dataView=new DataView(e.buffer,e.byteOffset,e.byteLength),r.positionReadCount=new Map,r.recursiveReadLimit=t,r}var _g,oc=E(()=>{"use strict";af();_g={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:Number.POSITIVE_INFINITY,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new nc({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new yo({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new ii({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new ii({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let r=t??this.position;return this.assertPosition(r+e-1),this.bytes.subarray(r,r+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let r=this.inspectBytes(e);return this.position+=t??e,r},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===Number.POSITIVE_INFINITY)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}}});function Am(e,t={}){typeof t.size<"u"&&it(e,{size:t.size});let r=se(e,t);return ge(r,t)}function Tm(e,t={}){let r=e;if(typeof t.size<"u"&&(it(r,{size:t.size}),r=$e(r)),r.length>1||r[0]>1)throw new Da(r);return!!r[0]}function Jt(e,t={}){typeof t.size<"u"&&it(e,{size:t.size});let r=se(e,t);return Te(r,t)}function Sm(e,t={}){let r=e;return typeof t.size<"u"&&(it(r,{size:t.size}),r=$e(r,{dir:"right"})),new TextDecoder().decode(r)}var Im=E(()=>{"use strict";Qs();En();Ve();V()});function mr(e,t){let r=typeof t=="string"?Ne(t):t,n=xo(r);if(ne(r)===0&&e.length>0)throw new vt;if(ne(t)&&ne(t)<32)throw new co({data:typeof t=="string"?t:se(t),params:e,size:ne(t)});let o=0,s=[];for(let i=0;i48?Am(o,{signed:r}):Jt(o,{signed:r}),32]}function Og(e,t,{staticPosition:r}){let n=t.components.length===0||t.components.some(({name:i})=>!i),o=n?[]:{},s=0;if(ai(t)){let i=Jt(e.readBytes(cf)),a=r+i;for(let c=0;c{"use strict";Ae();Sn();oc();wt();Ur();En();Im();He();V();Yt();Pm=32,cf=32});function sc(e){let{abi:t,data:r}=e,n=Tt(r,0,4);if(n==="0x")throw new vt;let s=[...t||[],rc,Em].find(i=>i.type==="error"&&n===Zt(Re(i)));if(!s)throw new uo(n,{docsPath:"/docs/contract/decodeErrorResult"});return{abiItem:s,args:"inputs"in s&&s.inputs&&s.inputs.length>0?mr(s.inputs,Tt(r,4)):void 0,errorName:s.name}}var uf=E(()=>{"use strict";si();Ae();Ur();ho();ci();ur()});var ee,Xe=E(()=>{"use strict";ee=(e,t,r)=>JSON.stringify(e,(n,o)=>{let s=typeof o=="bigint"?o.toString():o;return typeof t=="function"?t(n,s):s},r)});function pf({abiItem:e,args:t,includeFunctionName:r=!0,includeName:n=!1}){if("name"in e&&"inputs"in e&&e.inputs)return`${r?e.name:""}(${e.inputs.map((o,s)=>`${n&&o.name?`${o.name}: `:""}${typeof t[s]=="object"?ee(t[s]):t[s]}`).join(", ")})`}var Cm=E(()=>{"use strict";Xe()});var ic,km,ac=E(()=>{"use strict";ic={gwei:9,wei:18},km={ether:-9,wei:9}});function cc(e,t){let r=e.toString(),n=r.startsWith("-");n&&(r=r.slice(1)),r=r.padStart(t,"0");let[o,s]=[r.slice(0,r.length-t),r.slice(r.length-t)];return s=s.replace(/(0+)$/,""),`${n?"-":""}${o||"0"}${s?`.${s}`:""}`}var ff=E(()=>{"use strict"});function nt(e,t="wei"){return cc(e,ic[t])}var ui=E(()=>{"use strict";ac();ff()});function Fe(e,t="wei"){return cc(e,km[t])}var go=E(()=>{"use strict";ac();ff()});function _m(e){return e.reduce((t,{slot:r,value:n})=>`${t} ${r}: ${n} +`,"")}function Bm(e){return e.reduce((t,{address:r,...n})=>{let o=`${t} ${r}: +`;return n.nonce&&(o+=` nonce: ${n.nonce} +`),n.balance&&(o+=` balance: ${n.balance} +`),n.code&&(o+=` code: ${n.code} +`),n.state&&(o+=` state: +`,o+=_m(n.state)),n.stateDiff&&(o+=` stateDiff: +`,o+=_m(n.stateDiff)),o},` State Override: +`).slice(0,-1)}var uc,pc,lf=E(()=>{"use strict";Y();uc=class extends g{constructor({address:t}){super(`State for account "${t}" is set multiple times.`,{name:"AccountStateConflictError"})}},pc=class extends g{constructor(){super("state and stateDiff are set on the same account.",{name:"StateAssignmentConflictError"})}}});function In(e){let t=Object.entries(e).map(([n,o])=>o===void 0||o===!1?null:[n,o]).filter(Boolean),r=t.reduce((n,[o])=>Math.max(n,o.length),0);return t.map(([n,o])=>` ${`${n}:`.padEnd(r+1)} ${o}`).join(` +`)}var fc,lc,dc,mc,hc,wo,vo,yc,zt=E(()=>{"use strict";ui();go();Y();fc=class extends g{constructor(){super(["Cannot specify both a `gasPrice` and a `maxFeePerGas`/`maxPriorityFeePerGas`.","Use `maxFeePerGas`/`maxPriorityFeePerGas` for EIP-1559 compatible networks, and `gasPrice` for others."].join(` +`),{name:"FeeConflictError"})}},lc=class extends g{constructor({v:t}){super(`Invalid \`v\` value "${t}". Expected 27 or 28.`,{name:"InvalidLegacyVError"})}},dc=class extends g{constructor({transaction:t}){super("Cannot infer a transaction type from provided transaction.",{metaMessages:["Provided Transaction:","{",In(t),"}","","To infer the type, either provide:","- a `type` to the Transaction, or","- an EIP-1559 Transaction with `maxFeePerGas`, or","- an EIP-2930 Transaction with `gasPrice` & `accessList`, or","- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or","- an EIP-7702 Transaction with `authorizationList`, or","- a Legacy Transaction with `gasPrice`"],name:"InvalidSerializableTransactionError"})}},mc=class extends g{constructor({storageKey:t}){super(`Size for storage key "${t}" is invalid. Expected 32 bytes. Got ${Math.floor((t.length-2)/2)} bytes.`,{name:"InvalidStorageKeySizeError"})}},hc=class extends g{constructor(t,{account:r,docsPath:n,chain:o,data:s,gas:i,gasPrice:a,maxFeePerGas:c,maxPriorityFeePerGas:u,nonce:f,to:p,value:l}){let d=In({chain:o&&`${o?.name} (id: ${o?.id})`,from:r?.address,to:p,value:typeof l<"u"&&`${nt(l)} ${o?.nativeCurrency?.symbol||"ETH"}`,data:s,gas:i,gasPrice:typeof a<"u"&&`${Fe(a)} gwei`,maxFeePerGas:typeof c<"u"&&`${Fe(c)} gwei`,maxPriorityFeePerGas:typeof u<"u"&&`${Fe(u)} gwei`,nonce:f});super(t.shortMessage,{cause:t,docsPath:n,metaMessages:[...t.metaMessages?[...t.metaMessages," "]:[],"Request Arguments:",d].filter(Boolean),name:"TransactionExecutionError"}),Object.defineProperty(this,"cause",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=t}},wo=class extends g{constructor({blockHash:t,blockNumber:r,blockTag:n,hash:o,index:s}){let i="Transaction";n&&s!==void 0&&(i=`Transaction at block time "${n}" at index "${s}"`),t&&s!==void 0&&(i=`Transaction at block hash "${t}" at index "${s}"`),r&&s!==void 0&&(i=`Transaction at block number "${r}" at index "${s}"`),o&&(i=`Transaction with hash "${o}"`),super(`${i} could not be found.`,{name:"TransactionNotFoundError"})}},vo=class extends g{constructor({hash:t}){super(`Transaction receipt with hash "${t}" could not be found. The Transaction may not be processed on a block yet.`,{name:"TransactionReceiptNotFoundError"})}},yc=class extends g{constructor({hash:t}){super(`Timed out while waiting for transaction with hash "${t}" to be confirmed.`,{name:"WaitForTransactionReceiptTimeoutError"})}}});var Rm,Pn,xc=E(()=>{"use strict";Rm=e=>e,Pn=e=>e});var Eo,bc,Cn,gc,wc,Qt,Lr=E(()=>{"use strict";Pe();si();uf();ur();Cm();Mr();ui();go();Ae();Y();lf();zt();xc();Eo=class extends g{constructor(t,{account:r,docsPath:n,chain:o,data:s,gas:i,gasPrice:a,maxFeePerGas:c,maxPriorityFeePerGas:u,nonce:f,to:p,value:l,stateOverride:d}){let y=r?Z(r):void 0,x=In({from:y?.address,to:p,value:typeof l<"u"&&`${nt(l)} ${o?.nativeCurrency?.symbol||"ETH"}`,data:s,gas:i,gasPrice:typeof a<"u"&&`${Fe(a)} gwei`,maxFeePerGas:typeof c<"u"&&`${Fe(c)} gwei`,maxPriorityFeePerGas:typeof u<"u"&&`${Fe(u)} gwei`,nonce:f});d&&(x+=` +${Bm(d)}`),super(t.shortMessage,{cause:t,docsPath:n,metaMessages:[...t.metaMessages?[...t.metaMessages," "]:[],"Raw Call Arguments:",x].filter(Boolean),name:"CallExecutionError"}),Object.defineProperty(this,"cause",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=t}},bc=class extends g{constructor(t,{abi:r,args:n,contractAddress:o,docsPath:s,functionName:i,sender:a}){let c=ct({abi:r,args:n,name:i}),u=c?pf({abiItem:c,args:n,includeFunctionName:!1,includeName:!1}):void 0,f=c?Re(c,{includeName:!0}):void 0,p=In({address:o&&Rm(o),function:f,args:u&&u!=="()"&&`${[...Array(i?.length??0).keys()].map(()=>" ").join("")}${u}`,sender:a});super(t.shortMessage||`An unknown error occurred while executing the contract function "${i}".`,{cause:t,docsPath:s,metaMessages:[...t.metaMessages?[...t.metaMessages," "]:[],p&&"Contract Call:",p].filter(Boolean),name:"ContractFunctionExecutionError"}),Object.defineProperty(this,"abi",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"args",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"cause",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"contractAddress",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"formattedArgs",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"functionName",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"sender",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abi=r,this.args=n,this.cause=t,this.contractAddress=o,this.functionName=i,this.sender=a}},Cn=class extends g{constructor({abi:t,data:r,functionName:n,message:o}){let s,i,a,c;if(r&&r!=="0x")try{i=sc({abi:t,data:r});let{abiItem:f,errorName:p,args:l}=i;if(p==="Error")c=l[0];else if(p==="Panic"){let[d]=l;c=tc[d]}else{let d=f?Re(f,{includeName:!0}):void 0,y=f&&l?pf({abiItem:f,args:l,includeFunctionName:!1,includeName:!1}):void 0;a=[d?`Error: ${d}`:"",y&&y!=="()"?` ${[...Array(p?.length??0).keys()].map(()=>" ").join("")}${y}`:""]}}catch(f){s=f}else o&&(c=o);let u;s instanceof uo&&(u=s.signature,a=[`Unable to decode signature "${u}" as it was not found on the provided ABI.`,"Make sure you are using the correct ABI and that the error exists on it.",`You can look up the decoded signature here: https://openchain.xyz/signatures?query=${u}.`]),super(c&&c!=="execution reverted"||u?[`The contract function "${n}" reverted with the following ${u?"signature":"reason"}:`,c||u].join(` +`):`The contract function "${n}" reverted.`,{cause:s,metaMessages:a,name:"ContractFunctionRevertedError"}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"raw",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reason",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"signature",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=i,this.raw=r,this.reason=c,this.signature=u}},gc=class extends g{constructor({functionName:t}){super(`The contract function "${t}" returned no data ("0x").`,{metaMessages:["This could be due to any of the following:",` - The contract does not have the function "${t}",`," - The parameters passed to the contract function may be invalid, or"," - The address is not a contract."],name:"ContractFunctionZeroDataError"})}},wc=class extends g{constructor({factory:t}){super(`Deployment for counterfactual contract call failed${t?` for factory "${t}".`:""}`,{metaMessages:["Please ensure:","- The `factory` is a valid contract deployment factory (ie. Create2 Factory, ERC-4337 Factory, etc).","- The `factoryData` is a valid encoded function call for contract deployment function on the factory."],name:"CounterfactualDeploymentFailedError"})}},Qt=class extends g{constructor({data:t,message:r}){super(r||"",{name:"RawContractError"}),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=t}}});var St,Dr,pi,kn=E(()=>{"use strict";Xe();Y();xc();St=class extends g{constructor({body:t,cause:r,details:n,headers:o,status:s,url:i}){super("HTTP request failed.",{cause:r,details:n,metaMessages:[s&&`Status: ${s}`,`URL: ${Pn(i)}`,t&&`Request body: ${ee(t)}`].filter(Boolean),name:"HttpRequestError"}),Object.defineProperty(this,"body",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"headers",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"status",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"url",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.body=t,this.headers=o,this.status=s,this.url=i}},Dr=class extends g{constructor({body:t,error:r,url:n}){super("RPC Request failed.",{cause:r,details:r.message,metaMessages:[`URL: ${Pn(n)}`,`Request body: ${ee(t)}`],name:"RpcRequestError"}),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.code=r.code,this.data=r.data}},pi=class extends g{constructor({body:t,url:r}){super("The request took too long to respond.",{details:"The request timed out.",metaMessages:[`URL: ${Pn(r)}`,`Request body: ${ee(t)}`],name:"TimeoutError"})}}});var Mg,Je,ot,Ao,To,So,Io,hr,er,Po,Co,ko,Hr,_n,_o,Bn,Bo,Ro,$o,No,Fo,Oo,Uo,Mo,zo,Lo,Do,Ho,vc,fi=E(()=>{"use strict";Y();kn();Mg=-1,Je=class extends g{constructor(t,{code:r,docsPath:n,metaMessages:o,name:s,shortMessage:i}){super(i,{cause:t,docsPath:n,metaMessages:o||t?.metaMessages,name:s||"RpcError"}),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name=s||t.name,this.code=t instanceof Dr?t.code:r??Mg}},ot=class extends Je{constructor(t,r){super(t,r),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=r.data}},Ao=class e extends Je{constructor(t){super(t,{code:e.code,name:"ParseRpcError",shortMessage:"Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."})}};Object.defineProperty(Ao,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32700});To=class e extends Je{constructor(t){super(t,{code:e.code,name:"InvalidRequestRpcError",shortMessage:"JSON is not a valid request object."})}};Object.defineProperty(To,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32600});So=class e extends Je{constructor(t,{method:r}={}){super(t,{code:e.code,name:"MethodNotFoundRpcError",shortMessage:`The method${r?` "${r}"`:""} does not exist / is not available.`})}};Object.defineProperty(So,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32601});Io=class e extends Je{constructor(t){super(t,{code:e.code,name:"InvalidParamsRpcError",shortMessage:["Invalid parameters were provided to the RPC method.","Double check you have provided the correct parameters."].join(` +`)})}};Object.defineProperty(Io,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32602});hr=class e extends Je{constructor(t){super(t,{code:e.code,name:"InternalRpcError",shortMessage:"An internal error was received."})}};Object.defineProperty(hr,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32603});er=class e extends Je{constructor(t){super(t,{code:e.code,name:"InvalidInputRpcError",shortMessage:["Missing or invalid parameters.","Double check you have provided the correct parameters."].join(` +`)})}};Object.defineProperty(er,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32e3});Po=class e extends Je{constructor(t){super(t,{code:e.code,name:"ResourceNotFoundRpcError",shortMessage:"Requested resource not found."}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"ResourceNotFoundRpcError"})}};Object.defineProperty(Po,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32001});Co=class e extends Je{constructor(t){super(t,{code:e.code,name:"ResourceUnavailableRpcError",shortMessage:"Requested resource not available."})}};Object.defineProperty(Co,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32002});ko=class e extends Je{constructor(t){super(t,{code:e.code,name:"TransactionRejectedRpcError",shortMessage:"Transaction creation failed."})}};Object.defineProperty(ko,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32003});Hr=class e extends Je{constructor(t,{method:r}={}){super(t,{code:e.code,name:"MethodNotSupportedRpcError",shortMessage:`Method${r?` "${r}"`:""} is not supported.`})}};Object.defineProperty(Hr,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32004});_n=class e extends Je{constructor(t){super(t,{code:e.code,name:"LimitExceededRpcError",shortMessage:"Request exceeds defined limit."})}};Object.defineProperty(_n,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32005});_o=class e extends Je{constructor(t){super(t,{code:e.code,name:"JsonRpcVersionUnsupportedError",shortMessage:"Version of JSON-RPC protocol is not supported."})}};Object.defineProperty(_o,"code",{enumerable:!0,configurable:!0,writable:!0,value:-32006});Bn=class e extends ot{constructor(t){super(t,{code:e.code,name:"UserRejectedRequestError",shortMessage:"User rejected the request."})}};Object.defineProperty(Bn,"code",{enumerable:!0,configurable:!0,writable:!0,value:4001});Bo=class e extends ot{constructor(t){super(t,{code:e.code,name:"UnauthorizedProviderError",shortMessage:"The requested method and/or account has not been authorized by the user."})}};Object.defineProperty(Bo,"code",{enumerable:!0,configurable:!0,writable:!0,value:4100});Ro=class e extends ot{constructor(t,{method:r}={}){super(t,{code:e.code,name:"UnsupportedProviderMethodError",shortMessage:`The Provider does not support the requested method${r?` " ${r}"`:""}.`})}};Object.defineProperty(Ro,"code",{enumerable:!0,configurable:!0,writable:!0,value:4200});$o=class e extends ot{constructor(t){super(t,{code:e.code,name:"ProviderDisconnectedError",shortMessage:"The Provider is disconnected from all chains."})}};Object.defineProperty($o,"code",{enumerable:!0,configurable:!0,writable:!0,value:4900});No=class e extends ot{constructor(t){super(t,{code:e.code,name:"ChainDisconnectedError",shortMessage:"The Provider is not connected to the requested chain."})}};Object.defineProperty(No,"code",{enumerable:!0,configurable:!0,writable:!0,value:4901});Fo=class e extends ot{constructor(t){super(t,{code:e.code,name:"SwitchChainError",shortMessage:"An error occurred when attempting to switch chain."})}};Object.defineProperty(Fo,"code",{enumerable:!0,configurable:!0,writable:!0,value:4902});Oo=class e extends ot{constructor(t){super(t,{code:e.code,name:"UnsupportedNonOptionalCapabilityError",shortMessage:"This Wallet does not support a capability that was not marked as optional."})}};Object.defineProperty(Oo,"code",{enumerable:!0,configurable:!0,writable:!0,value:5700});Uo=class e extends ot{constructor(t){super(t,{code:e.code,name:"UnsupportedChainIdError",shortMessage:"This Wallet does not support the requested chain ID."})}};Object.defineProperty(Uo,"code",{enumerable:!0,configurable:!0,writable:!0,value:5710});Mo=class e extends ot{constructor(t){super(t,{code:e.code,name:"DuplicateIdError",shortMessage:"There is already a bundle submitted with this ID."})}};Object.defineProperty(Mo,"code",{enumerable:!0,configurable:!0,writable:!0,value:5720});zo=class e extends ot{constructor(t){super(t,{code:e.code,name:"UnknownBundleIdError",shortMessage:"This bundle id is unknown / has not been submitted"})}};Object.defineProperty(zo,"code",{enumerable:!0,configurable:!0,writable:!0,value:5730});Lo=class e extends ot{constructor(t){super(t,{code:e.code,name:"BundleTooLargeError",shortMessage:"The call bundle is too large for the Wallet to process."})}};Object.defineProperty(Lo,"code",{enumerable:!0,configurable:!0,writable:!0,value:5740});Do=class e extends ot{constructor(t){super(t,{code:e.code,name:"AtomicReadyWalletRejectedUpgradeError",shortMessage:"The Wallet can support atomicity after an upgrade, but the user rejected the upgrade."})}};Object.defineProperty(Do,"code",{enumerable:!0,configurable:!0,writable:!0,value:5750});Ho=class e extends ot{constructor(t){super(t,{code:e.code,name:"AtomicityNotSupportedError",shortMessage:"The wallet does not support atomic execution but the request requires it."})}};Object.defineProperty(Ho,"code",{enumerable:!0,configurable:!0,writable:!0,value:5760});vc=class extends Je{constructor(t){super(t,{name:"UnknownRpcError",shortMessage:"An unknown RPC error occurred."})}}});function Lg(e,t,r,n){if(typeof e.setBigUint64=="function")return e.setBigUint64(t,r,n);let o=BigInt(32),s=BigInt(4294967295),i=Number(r>>o&s),a=Number(r&s),c=n?4:0,u=n?0:4;e.setUint32(t+c,i,n),e.setUint32(t+u,a,n)}function Nm(e,t,r){return e&t^~e&r}function Fm(e,t,r){return e&t^e&r^t&r}var Ec,Om=E(()=>{"use strict";ti();Tn();Ec=class extends $r{constructor(t,r,n,o){super(),this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.blockLen=t,this.outputLen=r,this.padOffset=n,this.isLE=o,this.buffer=new Uint8Array(t),this.view=Va(this.buffer)}update(t){lr(this);let{view:r,buffer:n,blockLen:o}=this;t=Nr(t);let s=t.length;for(let i=0;io-i&&(this.process(n,0),i=0);for(let p=i;pf.length)throw new Error("_sha2: outputLen bigger than state");for(let p=0;p{"use strict";Om();Tn();Dg=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),jr=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),qr=new Uint32Array(64),df=class extends Ec{constructor(t=32){super(64,t,8,!1),this.A=jr[0]|0,this.B=jr[1]|0,this.C=jr[2]|0,this.D=jr[3]|0,this.E=jr[4]|0,this.F=jr[5]|0,this.G=jr[6]|0,this.H=jr[7]|0}get(){let{A:t,B:r,C:n,D:o,E:s,F:i,G:a,H:c}=this;return[t,r,n,o,s,i,a,c]}set(t,r,n,o,s,i,a,c){this.A=t|0,this.B=r|0,this.C=n|0,this.D=o|0,this.E=s|0,this.F=i|0,this.G=a|0,this.H=c|0}process(t,r){for(let p=0;p<16;p++,r+=4)qr[p]=t.getUint32(r,!1);for(let p=16;p<64;p++){let l=qr[p-15],d=qr[p-2],y=Ot(l,7)^Ot(l,18)^l>>>3,x=Ot(d,17)^Ot(d,19)^d>>>10;qr[p]=x+qr[p-7]+y+qr[p-16]|0}let{A:n,B:o,C:s,D:i,E:a,F:c,G:u,H:f}=this;for(let p=0;p<64;p++){let l=Ot(a,6)^Ot(a,11)^Ot(a,25),d=f+l+Nm(a,c,u)+Dg[p]+qr[p]|0,x=(Ot(n,2)^Ot(n,13)^Ot(n,22))+Fm(n,o,s)|0;f=u,u=c,c=a,a=i+d|0,i=s,s=o,o=n,n=d+x|0}n=n+this.A|0,o=o+this.B|0,s=s+this.C|0,i=i+this.D|0,a=a+this.E|0,c=c+this.F|0,u=u+this.G|0,f=f+this.H|0,this.set(n,o,s,i,a,c,u,f)}roundClean(){qr.fill(0)}destroy(){this.set(0,0,0,0,0,0,0,0),this.buffer.fill(0)}},Gr=Wa(()=>new df)});var Um=E(()=>{"use strict";mf()});var Ac,hf,Mm=E(()=>{"use strict";ti();Tn();Ac=class extends $r{constructor(t,r){super(),this.finished=!1,this.destroyed=!1,Dd(t);let n=Nr(r);if(this.iHash=t.create(),typeof this.iHash.update!="function")throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let o=this.blockLen,s=new Uint8Array(o);s.set(n.length>o?t.create().update(n).digest():n);for(let i=0;inew Ac(e,t).update(r).digest();hf.create=(e,t)=>new Ac(e,t)});function Rn(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function xr(e){if(!Rn(e))throw new Error("Uint8Array expected")}function jo(e,t){if(typeof t!="boolean")throw new Error(e+" boolean expected, got "+t)}function li(e){let t=e.toString(16);return t.length&1?"0"+t:t}function Dm(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);return e===""?gf:BigInt("0x"+e)}function qo(e){if(xr(e),Hm)return e.toHex();let t="";for(let r=0;r=yr._0&&e<=yr._9)return e-yr._0;if(e>=yr.A&&e<=yr.F)return e-(yr.A-10);if(e>=yr.a&&e<=yr.f)return e-(yr.a-10)}function di(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);if(Hm)return Uint8Array.fromHex(e);let t=e.length,r=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);let n=new Uint8Array(r);for(let o=0,s=0;ogf;e>>=bf,t+=1);return t}function qm(e,t,r){if(typeof e!="number"||e<2)throw new Error("hashLen must be a number");if(typeof t!="number"||t<2)throw new Error("qByteLen must be a number");if(typeof r!="function")throw new Error("hmacFn must be a function");let n=xf(e),o=xf(e),s=0,i=()=>{n.fill(1),o.fill(0),s=0},a=(...p)=>r(o,n,...p),c=(p=xf(0))=>{o=a(Lm([0]),p),n=a(),p.length!==0&&(o=a(Lm([1]),p),n=a())},u=()=>{if(s++>=1e3)throw new Error("drbg: tried 1000 values");let p=0,l=[];for(;p{i(),c(p);let d;for(;!(d=l(u()));)c();return i(),d}}function gr(e,t,r={}){let n=(o,s,i)=>{let a=jg[s];if(typeof a!="function")throw new Error("invalid validator function");let c=e[o];if(!(i&&c===void 0)&&!a(c,e))throw new Error("param "+String(o)+" is invalid. Expected "+s+", got "+c)};for(let[o,s]of Object.entries(t))n(o,s,!1);for(let[o,s]of Object.entries(r))n(o,s,!0);return e}function Ef(e){let t=new WeakMap;return(r,...n)=>{let o=t.get(r);if(o!==void 0)return o;let s=e(r,...n);return t.set(r,s),s}}var gf,bf,Hm,Hg,yr,yf,Nn,xf,Lm,jg,Go=E(()=>{"use strict";gf=BigInt(0),bf=BigInt(1);Hm=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Hg=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));yr={_0:48,_9:57,A:65,F:70,a:97,f:102};yf=e=>typeof e=="bigint"&&gf<=e;Nn=e=>(bf<new Uint8Array(e),Lm=e=>Uint8Array.from(e);jg={bigint:e=>typeof e=="bigint",function:e=>typeof e=="function",boolean:e=>typeof e=="boolean",string:e=>typeof e=="string",stringOrUint8Array:e=>typeof e=="string"||Rn(e),isSafeInteger:e=>Number.isSafeInteger(e),array:e=>Array.isArray(e),field:(e,t)=>t.Fp.isValid(e),hash:e=>typeof e=="function"&&Number.isSafeInteger(e.outputLen)}});function Ce(e,t){let r=e%t;return r>=Ue?r:t+r}function Wg(e,t,r){if(tUe;)t&Se&&(n=n*e%r),e=e*e%r,t>>=Se;return n}function xt(e,t,r){let n=e;for(;t-- >Ue;)n*=n,n%=r;return n}function Sc(e,t){if(e===Ue)throw new Error("invert: expected non-zero number");if(t<=Ue)throw new Error("invert: expected positive modulus, got "+t);let r=Ce(e,t),n=t,o=Ue,s=Se,i=Se,a=Ue;for(;r!==Ue;){let u=n/r,f=n%r,p=o-i*u,l=s-a*u;n=r,r=f,o=i,s=a,i=p,a=l}if(n!==Se)throw new Error("invert: does not exist");return Ce(o,t)}function Kg(e){let t=(e-Se)/Fn,r,n,o;for(r=e-Se,n=0;r%Fn===Ue;r/=Fn,n++);for(o=Fn;o1e3)throw new Error("Cannot find square root: likely non-prime P");if(n===1){let i=(e+Se)/Af;return function(c,u){let f=c.pow(u,i);if(!c.eql(c.sqr(f),u))throw new Error("Cannot find square root");return f}}let s=(r+Se)/Fn;return function(a,c){if(a.pow(c,t)===a.neg(a.ONE))throw new Error("Cannot find square root");let u=n,f=a.pow(a.mul(a.ONE,o),r),p=a.pow(c,s),l=a.pow(c,r);for(;!a.eql(l,a.ONE);){if(a.eql(l,a.ZERO))return a.ZERO;let d=1;for(let x=a.sqr(l);d(n[o]="function",n),t);return gr(e,r)}function Xg(e,t,r){if(rUe;)r&Se&&(n=e.mul(n,o)),o=e.sqr(o),r>>=Se;return n}function Jg(e,t){let r=new Array(t.length),n=t.reduce((s,i,a)=>e.is0(i)?s:(r[a]=s,e.mul(s,i)),e.ONE),o=e.inv(n);return t.reduceRight((s,i,a)=>e.is0(i)?s:(r[a]=e.mul(s,r[a]),e.mul(s,i)),o),r}function Tf(e,t){let r=t!==void 0?t:e.toString(2).length,n=Math.ceil(r/8);return{nBitLength:r,nByteLength:n}}function Pc(e,t,r=!1,n={}){if(e<=Ue)throw new Error("invalid field: expected ORDER > 0, got "+e);let{nBitLength:o,nByteLength:s}=Tf(e,t);if(s>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");let i,a=Object.freeze({ORDER:e,isLE:r,BITS:o,BYTES:s,MASK:Nn(o),ZERO:Ue,ONE:Se,create:c=>Ce(c,e),isValid:c=>{if(typeof c!="bigint")throw new Error("invalid field element: expected bigint, got "+typeof c);return Ue<=c&&cc===Ue,isOdd:c=>(c&Se)===Se,neg:c=>Ce(-c,e),eql:(c,u)=>c===u,sqr:c=>Ce(c*c,e),add:(c,u)=>Ce(c+u,e),sub:(c,u)=>Ce(c-u,e),mul:(c,u)=>Ce(c*u,e),pow:(c,u)=>Xg(a,c,u),div:(c,u)=>Ce(c*Sc(u,e),e),sqrN:c=>c*c,addN:(c,u)=>c+u,subN:(c,u)=>c-u,mulN:(c,u)=>c*u,inv:c=>Sc(c,e),sqrt:n.sqrt||(c=>(i||(i=Yg(e)),i(a,c))),invertBatch:c=>Jg(a,c),cmov:(c,u,f)=>f?u:c,toBytes:c=>r?vf(c,s):tr(c,s),fromBytes:c=>{if(c.length!==s)throw new Error("Field.fromBytes: expected "+s+" bytes, got "+c.length);return r?wf(c):ut(c)}});return Object.freeze(a)}function Wm(e){if(typeof e!="bigint")throw new Error("field order must be bigint");let t=e.toString(2).length;return Math.ceil(t/8)}function Sf(e){let t=Wm(e);return t+Math.ceil(t/2)}function Km(e,t,r=!1){let n=e.length,o=Wm(t),s=Sf(t);if(n<16||n1024)throw new Error("expected "+s+"-1024 bytes of input, got "+n);let i=r?wf(e):ut(e),a=Ce(i,t-Se)+Se;return r?vf(a,o):tr(a,o)}var Ue,Se,Fn,qg,Af,Gm,Vm,Gg,Vg,Zg,mi=E(()=>{"use strict";Go();Ue=BigInt(0),Se=BigInt(1),Fn=BigInt(2),qg=BigInt(3),Af=BigInt(4),Gm=BigInt(5),Vm=BigInt(8),Gg=BigInt(9),Vg=BigInt(16);Zg=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"]});function If(e,t){let r=t.negate();return e?r:t}function Xm(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw new Error("invalid window size, expected [1.."+t+"], got W="+e)}function Pf(e,t){Xm(e,t);let r=Math.ceil(t/e)+1,n=2**(e-1),o=2**e,s=Nn(e),i=BigInt(e);return{windows:r,windowSize:n,mask:s,maxNumber:o,shiftBy:i}}function Zm(e,t,r){let{windowSize:n,mask:o,maxNumber:s,shiftBy:i}=r,a=Number(e&o),c=e>>i;a>n&&(a-=s,c+=_f);let u=t*n,f=u+Math.abs(a)-1,p=a===0,l=a<0,d=t%2!==0;return{nextN:c,offset:f,isZero:p,isNeg:l,isNegF:d,offsetF:u}}function Qg(e,t){if(!Array.isArray(e))throw new Error("array expected");e.forEach((r,n)=>{if(!(r instanceof t))throw new Error("invalid point at index "+n)})}function e1(e,t){if(!Array.isArray(e))throw new Error("array of scalars expected");e.forEach((r,n)=>{if(!t.isValid(r))throw new Error("invalid scalar at index "+n)})}function kf(e){return Jm.get(e)||1}function Qm(e,t){return{constTimeNegate:If,hasPrecomputes(r){return kf(r)!==1},unsafeLadder(r,n,o=e.ZERO){let s=r;for(;n>Ym;)n&_f&&(o=o.add(s)),s=s.double(),n>>=_f;return o},precomputeWindow(r,n){let{windows:o,windowSize:s}=Pf(n,t),i=[],a=r,c=a;for(let u=0;u12?s-3:s>4?s-2:s?2:1,a=Nn(i),c=new Array(Number(a)+1).fill(o),u=Math.floor((t.BITS-1)/i)*i,f=o;for(let p=u;p>=0;p-=i){c.fill(o);for(let d=0;d>BigInt(p)&a);c[x]=c[x].add(r[d])}let l=o;for(let d=c.length-1,y=o;d>0;d--)y=y.add(c[d]),l=l.add(y);if(f=f.add(l),p!==0)for(let d=0;d{"use strict";mi();Go();Ym=BigInt(0),_f=BigInt(1);Cf=new WeakMap,Jm=new WeakMap});function rh(e){e.lowS!==void 0&&jo("lowS",e.lowS),e.prehash!==void 0&&jo("prehash",e.prehash)}function t1(e){let t=Bf(e);gr(t,{a:"field",b:"field"},{allowedPrivateKeyLengths:"array",wrapPrivateKey:"boolean",isTorsionFree:"function",clearCofactor:"function",allowInfinityPoint:"boolean",fromBytes:"function",toBytes:"function"});let{endo:r,Fp:n,a:o}=t;if(r){if(!n.eql(o,n.ZERO))throw new Error("invalid endomorphism, can only be defined for Koblitz curves that have a=0");if(typeof r!="object"||typeof r.beta!="bigint"||typeof r.splitScalar!="function")throw new Error("invalid endomorphism, expected beta: bigint and splitScalar: function")}return Object.freeze({...t})}function r1(e){let t=t1(e),{Fp:r}=t,n=Pc(t.n,t.nBitLength),o=t.toBytes||((x,m,h)=>{let b=m.toAffine();return st(Uint8Array.from([4]),r.toBytes(b.x),r.toBytes(b.y))}),s=t.fromBytes||(x=>{let m=x.subarray(1),h=r.fromBytes(m.subarray(0,r.BYTES)),b=r.fromBytes(m.subarray(r.BYTES,2*r.BYTES));return{x:h,y:b}});function i(x){let{a:m,b:h}=t,b=r.sqr(x),v=r.mul(b,x);return r.add(r.add(v,r.mul(x,m)),h)}if(!r.eql(r.sqr(t.Gy),i(t.Gx)))throw new Error("bad generator point: equation left != right");function a(x){return $n(x,le,t.n)}function c(x){let{allowedPrivateKeyLengths:m,nByteLength:h,wrapPrivateKey:b,n:v}=t;if(m&&typeof x!="bigint"){if(Rn(x)&&(x=qo(x)),typeof x!="string"||!m.includes(x.length))throw new Error("invalid private key");x=x.padStart(h*2,"0")}let A;try{A=typeof x=="bigint"?x:ut(Oe("private key",x,h))}catch{throw new Error("invalid private key, expected hex or "+h+" bytes, got "+typeof x)}return b&&(A=Ce(A,v)),br("private key",A,le,v),A}function u(x){if(!(x instanceof l))throw new Error("ProjectivePoint expected")}let f=Ef((x,m)=>{let{px:h,py:b,pz:v}=x;if(r.eql(v,r.ONE))return{x:h,y:b};let A=x.is0();m==null&&(m=A?r.ONE:r.inv(v));let k=r.mul(h,m),S=r.mul(b,m),T=r.mul(v,m);if(A)return{x:r.ZERO,y:r.ZERO};if(!r.eql(T,r.ONE))throw new Error("invZ was invalid");return{x:k,y:S}}),p=Ef(x=>{if(x.is0()){if(t.allowInfinityPoint&&!r.is0(x.py))return;throw new Error("bad point: ZERO")}let{x:m,y:h}=x.toAffine();if(!r.isValid(m)||!r.isValid(h))throw new Error("bad point: x or y not FE");let b=r.sqr(h),v=i(m);if(!r.eql(b,v))throw new Error("bad point: equation left != right");if(!x.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});class l{constructor(m,h,b){if(m==null||!r.isValid(m))throw new Error("x required");if(h==null||!r.isValid(h))throw new Error("y required");if(b==null||!r.isValid(b))throw new Error("z required");this.px=m,this.py=h,this.pz=b,Object.freeze(this)}static fromAffine(m){let{x:h,y:b}=m||{};if(!m||!r.isValid(h)||!r.isValid(b))throw new Error("invalid affine point");if(m instanceof l)throw new Error("projective point not allowed");let v=A=>r.eql(A,r.ZERO);return v(h)&&v(b)?l.ZERO:new l(h,b,r.ONE)}get x(){return this.toAffine().x}get y(){return this.toAffine().y}static normalizeZ(m){let h=r.invertBatch(m.map(b=>b.pz));return m.map((b,v)=>b.toAffine(h[v])).map(l.fromAffine)}static fromHex(m){let h=l.fromAffine(s(Oe("pointHex",m)));return h.assertValidity(),h}static fromPrivateKey(m){return l.BASE.multiply(c(m))}static msm(m,h){return eh(l,n,m,h)}_setWindowSize(m){y.setWindowSize(this,m)}assertValidity(){p(this)}hasEvenY(){let{y:m}=this.toAffine();if(r.isOdd)return!r.isOdd(m);throw new Error("Field doesn't support isOdd")}equals(m){u(m);let{px:h,py:b,pz:v}=this,{px:A,py:k,pz:S}=m,T=r.eql(r.mul(h,S),r.mul(A,v)),_=r.eql(r.mul(b,S),r.mul(k,v));return T&&_}negate(){return new l(this.px,r.neg(this.py),this.pz)}double(){let{a:m,b:h}=t,b=r.mul(h,Cc),{px:v,py:A,pz:k}=this,S=r.ZERO,T=r.ZERO,_=r.ZERO,C=r.mul(v,v),D=r.mul(A,A),z=r.mul(k,k),L=r.mul(v,A);return L=r.add(L,L),_=r.mul(v,k),_=r.add(_,_),S=r.mul(m,_),T=r.mul(b,z),T=r.add(S,T),S=r.sub(D,T),T=r.add(D,T),T=r.mul(S,T),S=r.mul(L,S),_=r.mul(b,_),z=r.mul(m,z),L=r.sub(C,z),L=r.mul(m,L),L=r.add(L,_),_=r.add(C,C),C=r.add(_,C),C=r.add(C,z),C=r.mul(C,L),T=r.add(T,C),z=r.mul(A,k),z=r.add(z,z),C=r.mul(z,L),S=r.sub(S,C),_=r.mul(z,D),_=r.add(_,_),_=r.add(_,_),new l(S,T,_)}add(m){u(m);let{px:h,py:b,pz:v}=this,{px:A,py:k,pz:S}=m,T=r.ZERO,_=r.ZERO,C=r.ZERO,D=t.a,z=r.mul(t.b,Cc),L=r.mul(h,A),ae=r.mul(b,k),B=r.mul(v,S),O=r.add(h,b),N=r.add(A,k);O=r.mul(O,N),N=r.add(L,ae),O=r.sub(O,N),N=r.add(h,v);let G=r.add(A,S);return N=r.mul(N,G),G=r.add(L,B),N=r.sub(N,G),G=r.add(b,v),T=r.add(k,S),G=r.mul(G,T),T=r.add(ae,B),G=r.sub(G,T),C=r.mul(D,N),T=r.mul(z,B),C=r.add(T,C),T=r.sub(ae,C),C=r.add(ae,C),_=r.mul(T,C),ae=r.add(L,L),ae=r.add(ae,L),B=r.mul(D,B),N=r.mul(z,N),ae=r.add(ae,B),B=r.sub(L,B),B=r.mul(D,B),N=r.add(N,B),L=r.mul(ae,N),_=r.add(_,L),L=r.mul(G,N),T=r.mul(O,T),T=r.sub(T,L),L=r.mul(O,ae),C=r.mul(G,C),C=r.add(C,L),new l(T,_,C)}subtract(m){return this.add(m.negate())}is0(){return this.equals(l.ZERO)}wNAF(m){return y.wNAFCached(this,m,l.normalizeZ)}multiplyUnsafe(m){let{endo:h,n:b}=t;br("scalar",m,Lt,b);let v=l.ZERO;if(m===Lt)return v;if(this.is0()||m===le)return this;if(!h||y.hasPrecomputes(this))return y.wNAFCachedUnsafe(this,m,l.normalizeZ);let{k1neg:A,k1:k,k2neg:S,k2:T}=h.splitScalar(m),_=v,C=v,D=this;for(;k>Lt||T>Lt;)k&le&&(_=_.add(D)),T&le&&(C=C.add(D)),D=D.double(),k>>=le,T>>=le;return A&&(_=_.negate()),S&&(C=C.negate()),C=new l(r.mul(C.px,h.beta),C.py,C.pz),_.add(C)}multiply(m){let{endo:h,n:b}=t;br("scalar",m,le,b);let v,A;if(h){let{k1neg:k,k1:S,k2neg:T,k2:_}=h.splitScalar(m),{p:C,f:D}=this.wNAF(S),{p:z,f:L}=this.wNAF(_);C=y.constTimeNegate(k,C),z=y.constTimeNegate(T,z),z=new l(r.mul(z.px,h.beta),z.py,z.pz),v=C.add(z),A=D.add(L)}else{let{p:k,f:S}=this.wNAF(m);v=k,A=S}return l.normalizeZ([v,A])[0]}multiplyAndAddUnsafe(m,h,b){let v=l.BASE,A=(S,T)=>T===Lt||T===le||!S.equals(v)?S.multiplyUnsafe(T):S.multiply(T),k=A(this,h).add(A(m,b));return k.is0()?void 0:k}toAffine(m){return f(this,m)}isTorsionFree(){let{h:m,isTorsionFree:h}=t;if(m===le)return!0;if(h)return h(l,this);throw new Error("isTorsionFree() has not been declared for the elliptic curve")}clearCofactor(){let{h:m,clearCofactor:h}=t;return m===le?this:h?h(l,this):this.multiplyUnsafe(t.h)}toRawBytes(m=!0){return jo("isCompressed",m),this.assertValidity(),o(l,this,m)}toHex(m=!0){return jo("isCompressed",m),qo(this.toRawBytes(m))}}l.BASE=new l(t.Gx,t.Gy,r.ONE),l.ZERO=new l(r.ZERO,r.ONE,r.ZERO);let d=t.nBitLength,y=Qm(l,t.endo?Math.ceil(d/2):d);return{CURVE:t,ProjectivePoint:l,normPrivateKeyToScalar:c,weierstrassEquation:i,isWithinCurveOrder:a}}function n1(e){let t=Bf(e);return gr(t,{hash:"hash",hmac:"function",randomBytes:"function"},{bits2int:"function",bits2int_modN:"function",lowS:"boolean"}),Object.freeze({lowS:!0,...t})}function oh(e){let t=n1(e),{Fp:r,n}=t,o=r.BYTES+1,s=2*r.BYTES+1;function i(B){return Ce(B,n)}function a(B){return Sc(B,n)}let{ProjectivePoint:c,normPrivateKeyToScalar:u,weierstrassEquation:f,isWithinCurveOrder:p}=r1({...t,toBytes(B,O,N){let G=O.toAffine(),j=r.toBytes(G.x),F=st;return jo("isCompressed",N),N?F(Uint8Array.from([O.hasEvenY()?2:3]),j):F(Uint8Array.from([4]),j,r.toBytes(G.y))},fromBytes(B){let O=B.length,N=B[0],G=B.subarray(1);if(O===o&&(N===2||N===3)){let j=ut(G);if(!$n(j,le,r.ORDER))throw new Error("Point is not on curve");let F=f(j),te;try{te=r.sqrt(F)}catch(P){let W=P instanceof Error?": "+P.message:"";throw new Error("Point is not on curve"+W)}let he=(te&le)===le;return(N&1)===1!==he&&(te=r.neg(te)),{x:j,y:te}}else if(O===s&&N===4){let j=r.fromBytes(G.subarray(0,r.BYTES)),F=r.fromBytes(G.subarray(r.BYTES,2*r.BYTES));return{x:j,y:F}}else{let j=o,F=s;throw new Error("invalid Point, expected length of "+j+", or uncompressed "+F+", got "+O)}}}),l=B=>qo(tr(B,t.nByteLength));function d(B){let O=n>>le;return B>O}function y(B){return d(B)?i(-B):B}let x=(B,O,N)=>ut(B.slice(O,N));class m{constructor(O,N,G){br("r",O,le,n),br("s",N,le,n),this.r=O,this.s=N,G!=null&&(this.recovery=G),Object.freeze(this)}static fromCompact(O){let N=t.nByteLength;return O=Oe("compactSignature",O,N*2),new m(x(O,0,N),x(O,N,2*N))}static fromDER(O){let{r:N,s:G}=wr.toSig(Oe("DER",O));return new m(N,G)}assertValidity(){}addRecoveryBit(O){return new m(this.r,this.s,O)}recoverPublicKey(O){let{r:N,s:G,recovery:j}=this,F=S(Oe("msgHash",O));if(j==null||![0,1,2,3].includes(j))throw new Error("recovery id invalid");let te=j===2||j===3?N+t.n:N;if(te>=r.ORDER)throw new Error("recovery id 2 or 3 invalid");let he=(j&1)===0?"02":"03",w=c.fromHex(he+l(te)),P=a(te),W=i(-F*P),J=i(G*P),X=c.BASE.multiplyAndAddUnsafe(w,W,J);if(!X)throw new Error("point at infinify");return X.assertValidity(),X}hasHighS(){return d(this.s)}normalizeS(){return this.hasHighS()?new m(this.r,i(-this.s),this.recovery):this}toDERRawBytes(){return di(this.toDERHex())}toDERHex(){return wr.hexFromSig({r:this.r,s:this.s})}toCompactRawBytes(){return di(this.toCompactHex())}toCompactHex(){return l(this.r)+l(this.s)}}let h={isValidPrivateKey(B){try{return u(B),!0}catch{return!1}},normPrivateKeyToScalar:u,randomPrivateKey:()=>{let B=Sf(t.n);return Km(t.randomBytes(B),t.n)},precompute(B=8,O=c.BASE){return O._setWindowSize(B),O.multiply(BigInt(3)),O}};function b(B,O=!0){return c.fromPrivateKey(B).toRawBytes(O)}function v(B){let O=Rn(B),N=typeof B=="string",G=(O||N)&&B.length;return O?G===o||G===s:N?G===2*o||G===2*s:B instanceof c}function A(B,O,N=!0){if(v(B))throw new Error("first arg must be private key");if(!v(O))throw new Error("second arg must be public key");return c.fromHex(O).multiply(u(B)).toRawBytes(N)}let k=t.bits2int||function(B){if(B.length>8192)throw new Error("input is too large");let O=ut(B),N=B.length*8-t.nBitLength;return N>0?O>>BigInt(N):O},S=t.bits2int_modN||function(B){return i(k(B))},T=Nn(t.nBitLength);function _(B){return br("num < 2^"+t.nBitLength,B,Lt,T),tr(B,t.nByteLength)}function C(B,O,N=D){if(["recovered","canonical"].some(ue=>ue in N))throw new Error("sign() legacy options not supported");let{hash:G,randomBytes:j}=t,{lowS:F,prehash:te,extraEntropy:he}=N;F==null&&(F=!0),B=Oe("msgHash",B),rh(N),te&&(B=Oe("prehashed msgHash",G(B)));let w=S(B),P=u(O),W=[_(P),_(w)];if(he!=null&&he!==!1){let ue=he===!0?j(r.BYTES):he;W.push(Oe("extraEntropy",ue))}let J=st(...W),X=w;function ye(ue){let pe=k(ue);if(!p(pe))return;let me=a(pe),ze=c.BASE.multiply(pe).toAffine(),Pr=i(ze.x);if(Pr===Lt)return;let Qn=i(me*i(X+Pr*P));if(Qn===Lt)return;let hn=(ze.x===Pr?0:2)|Number(ze.y&le),Sp=Qn;return F&&d(Qn)&&(Sp=y(Qn),hn^=1),new m(Pr,Sp,hn)}return{seed:J,k2sig:ye}}let D={lowS:t.lowS,prehash:!1},z={lowS:t.lowS,prehash:!1};function L(B,O,N=D){let{seed:G,k2sig:j}=C(B,O,N),F=t;return qm(F.hash.outputLen,F.nByteLength,F.hmac)(G,j)}c.BASE._setWindowSize(8);function ae(B,O,N,G=z){let j=B;O=Oe("msgHash",O),N=Oe("publicKey",N);let{lowS:F,prehash:te,format:he}=G;if(rh(G),"strict"in G)throw new Error("options.strict was renamed to lowS");if(he!==void 0&&he!=="compact"&&he!=="der")throw new Error("format must be compact or der");let w=typeof j=="string"||Rn(j),P=!w&&!he&&typeof j=="object"&&j!==null&&typeof j.r=="bigint"&&typeof j.s=="bigint";if(!w&&!P)throw new Error("invalid signature, expected Uint8Array, hex string or Signature instance");let W,J;try{if(P&&(W=new m(j.r,j.s)),w){try{he!=="compact"&&(W=m.fromDER(j))}catch(hn){if(!(hn instanceof wr.Err))throw hn}!W&&he!=="der"&&(W=m.fromCompact(j))}J=c.fromHex(N)}catch{return!1}if(!W||F&&W.hasHighS())return!1;te&&(O=t.hash(O));let{r:X,s:ye}=W,ue=S(O),pe=a(ye),me=i(ue*pe),ze=i(X*pe),Pr=c.BASE.multiplyAndAddUnsafe(J,me,ze)?.toAffine();return Pr?i(Pr.x)===X:!1}return{CURVE:t,getPublicKey:b,getSharedSecret:A,sign:L,verify:ae,ProjectivePoint:c,Signature:m,utils:h}}function o1(e,t){let r=e.ORDER,n=Lt;for(let y=r-le;y%Vr===Lt;y/=Vr)n+=le;let o=n,s=Vr<{let m=p,h=e.pow(x,u),b=e.sqr(h);b=e.mul(b,x);let v=e.mul(y,b);v=e.pow(v,c),v=e.mul(v,h),h=e.mul(v,x),b=e.mul(v,y);let A=e.mul(b,h);v=e.pow(A,f);let k=e.eql(v,e.ONE);h=e.mul(b,l),v=e.mul(A,m),b=e.cmov(h,b,k),A=e.cmov(v,A,k);for(let S=o;S>le;S--){let T=S-Vr;T=Vr<{let b=e.sqr(h),v=e.mul(m,h);b=e.mul(b,v);let A=e.pow(b,y);A=e.mul(A,v);let k=e.mul(A,x),S=e.mul(e.sqr(A),h),T=e.eql(S,m),_=e.cmov(k,A,T);return{isValid:T,value:_}}}return d}function sh(e,t){if(Ic(e),!e.isValid(t.A)||!e.isValid(t.B)||!e.isValid(t.Z))throw new Error("mapToCurveSimpleSWU: invalid opts");let r=o1(e,t.Z);if(!e.isOdd)throw new Error("Fp.isOdd is not implemented!");return n=>{let o,s,i,a,c,u,f,p;o=e.sqr(n),o=e.mul(o,t.Z),s=e.sqr(o),s=e.add(s,o),i=e.add(s,e.ONE),i=e.mul(i,t.B),a=e.cmov(t.Z,e.neg(s),!e.eql(s,e.ZERO)),a=e.mul(a,t.A),s=e.sqr(i),u=e.sqr(a),c=e.mul(u,t.A),s=e.add(s,c),s=e.mul(s,i),u=e.mul(u,a),c=e.mul(u,t.B),s=e.add(s,c),f=e.mul(o,i);let{isValid:l,value:d}=r(s,u);p=e.mul(o,n),p=e.mul(p,d),f=e.cmov(f,i,l),p=e.cmov(p,d,l);let y=e.isOdd(n)===e.isOdd(p);return p=e.cmov(e.neg(p),p,y),f=e.div(f,a),{x:f,y:p}}}var Rf,wr,Lt,le,Vr,Cc,nh,$f=E(()=>{"use strict";th();mi();Go();Rf=class extends Error{constructor(t=""){super(t)}},wr={Err:Rf,_tlv:{encode:(e,t)=>{let{Err:r}=wr;if(e<0||e>256)throw new r("tlv.encode: wrong tag");if(t.length&1)throw new r("tlv.encode: unpadded data");let n=t.length/2,o=li(n);if(o.length/2&128)throw new r("tlv.encode: long form length too big");let s=n>127?li(o.length/2|128):"";return li(e)+s+o+t},decode(e,t){let{Err:r}=wr,n=0;if(e<0||e>256)throw new r("tlv.encode: wrong tag");if(t.length<2||t[n++]!==e)throw new r("tlv.decode: wrong tlv");let o=t[n++],s=!!(o&128),i=0;if(!s)i=o;else{let c=o&127;if(!c)throw new r("tlv.decode(long): indefinite length not supported");if(c>4)throw new r("tlv.decode(long): byte length is too big");let u=t.subarray(n,n+c);if(u.length!==c)throw new r("tlv.decode: length bytes not complete");if(u[0]===0)throw new r("tlv.decode(long): zero leftmost byte");for(let f of u)i=i<<8|f;if(n+=c,i<128)throw new r("tlv.decode(long): not minimal encoding")}let a=t.subarray(n,n+i);if(a.length!==i)throw new r("tlv.decode: wrong value length");return{v:a,l:t.subarray(n+i)}}},_int:{encode(e){let{Err:t}=wr;if(ehf(e,t,Xd(...r)),randomBytes:Ka}}function ih(e,t){let r=n=>oh({...e,...s1(n)});return{...r(t),create:r}}var ah=E(()=>{"use strict";Mm();Tn();$f();});function Wr(e,t){if(hi(e),hi(t),e<0||e>=1<<8*t)throw new Error("invalid I2OSP input: "+e);let r=Array.from({length:t}).fill(0);for(let n=t-1;n>=0;n--)r[n]=e&255,e>>>=8;return new Uint8Array(r)}function a1(e,t){let r=new Uint8Array(e.length);for(let n=0;n255&&(t=n(st(Tc("H2C-OVERSIZE-DST-"),t)));let{outputLen:o,blockLen:s}=n,i=Math.ceil(r/o);if(r>65535||i>255)throw new Error("expand_message_xmd: invalid lenInBytes");let a=st(t,Wr(t.length,1)),c=Wr(0,s),u=Wr(r,2),f=new Array(i),p=n(st(c,e,u,Wr(0,1),a));f[0]=n(st(p,Wr(1,1),a));for(let d=1;d<=i;d++){let y=[a1(p,f[d-1]),Wr(d+1,1),a];f[d]=n(st(...y))}return st(...f).slice(0,r)}function u1(e,t,r,n,o){if(xr(e),xr(t),hi(r),t.length>255){let s=Math.ceil(2*n/8);t=o.create({dkLen:s}).update(Tc("H2C-OVERSIZE-DST-")).update(t).digest()}if(r>65535||t.length>255)throw new Error("expand_message_xof: invalid lenInBytes");return o.create({dkLen:r}).update(e).update(Wr(r,2)).update(t).update(Wr(t.length,1)).digest()}function ch(e,t,r){gr(r,{DST:"stringOrUint8Array",p:"bigint",m:"isSafeInteger",k:"isSafeInteger",hash:"hash"});let{p:n,k:o,m:s,hash:i,expand:a,DST:c}=r;xr(e),hi(t);let u=typeof c=="string"?Tc(c):c,f=n.toString(2).length,p=Math.ceil((f+o)/8),l=t*s*p,d;if(a==="xmd")d=c1(e,u,l,i);else if(a==="xof")d=u1(e,u,l,o,i);else if(a==="_internal_pass")d=e;else throw new Error('expand must be "xmd" or "xof"');let y=new Array(t);for(let x=0;xArray.from(n).reverse());return(n,o)=>{let[s,i,a,c]=r.map(u=>u.reduce((f,p)=>e.add(e.mul(f,n),p)));if(e.is0(i)||e.is0(c))throw new Error("bad point: ZERO");return n=e.div(s,i),o=e.mul(o,e.div(a,c)),{x:n,y:o}}}function ph(e,t,r){if(typeof t!="function")throw new Error("mapToCurve() must be defined");return{hashToCurve(n,o){let s=ch(n,2,{...r,DST:r.DST,...o}),i=e.fromAffine(t(s[0])),a=e.fromAffine(t(s[1])),c=i.add(a).clearCofactor();return c.assertValidity(),c},encodeToCurve(n,o){let s=ch(n,1,{...r,DST:r.encodeDST,...o}),i=e.fromAffine(t(s[0])).clearCofactor();return i.assertValidity(),i},mapToCurve(n){if(!Array.isArray(n))throw new Error("mapToCurve: expected array of bigints");for(let s of n)if(typeof s!="bigint")throw new Error("mapToCurve: expected array of bigints");let o=e.fromAffine(t(n)).clearCofactor();return o.assertValidity(),o}}}var i1,fh=E(()=>{"use strict";mi();Go();i1=ut});var wh={};Ip(wh,{encodeToCurve:()=>x1,hashToCurve:()=>y1,schnorr:()=>d1,secp256k1:()=>On});function mh(e){let t=bi,r=BigInt(3),n=BigInt(6),o=BigInt(11),s=BigInt(22),i=BigInt(23),a=BigInt(44),c=BigInt(88),u=e*e*e%t,f=u*u*e%t,p=xt(f,r,t)*f%t,l=xt(p,r,t)*f%t,d=xt(l,_c,t)*u%t,y=xt(d,o,t)*d%t,x=xt(y,s,t)*y%t,m=xt(x,a,t)*x%t,h=xt(m,c,t)*m%t,b=xt(h,a,t)*x%t,v=xt(b,r,t)*f%t,A=xt(v,i,t)*y%t,k=xt(A,n,t)*u%t,S=xt(k,_c,t);if(!Kr.eql(Kr.sqr(S),e))throw new Error("Cannot find square root");return S}function Bc(e,...t){let r=dh[e];if(r===void 0){let n=Gr(Uint8Array.from(e,o=>o.charCodeAt(0)));r=st(n,n),dh[e]=r}return Gr(st(r,...t))}function Of(e){let t=On.utils.normPrivateKeyToScalar(e),r=Mf.fromPrivateKey(t);return{scalar:r.hasEvenY()?t:xi(-t),bytes:Uf(r)}}function yh(e){br("x",e,yi,bi);let t=Nf(e*e),r=Nf(t*e+BigInt(7)),n=mh(r);n%_c!==hh&&(n=Nf(-n));let o=new Mf(e,n,yi);return o.assertValidity(),o}function xh(...e){return xi(Vo(Bc("BIP0340/challenge",...e)))}function f1(e){return Of(e).bytes}function l1(e,t,r=Ka(32)){let n=Oe("message",e),{bytes:o,scalar:s}=Of(t),i=Oe("auxRand",r,32),a=Ff(s^Vo(Bc("BIP0340/aux",i))),c=Bc("BIP0340/nonce",a,o,n),u=xi(Vo(c));if(u===hh)throw new Error("sign failed: k is zero");let{bytes:f,scalar:p}=Of(u),l=xh(f,o,n),d=new Uint8Array(64);if(d.set(f,0),d.set(Ff(xi(p+l*s)),32),!bh(d,n,o))throw new Error("sign: Invalid signature produced");return d}function bh(e,t,r){let n=Oe("signature",e,64),o=Oe("message",t),s=Oe("publicKey",r,32);try{let i=yh(Vo(s)),a=Vo(n.subarray(0,32));if(!$n(a,yi,bi))return!1;let c=Vo(n.subarray(32,64));if(!$n(c,yi,kc))return!1;let u=xh(Ff(a),Uf(i),o),f=p1(i,c,xi(-u));return!(!f||!f.hasEvenY()||f.toAffine().x!==a)}catch{return!1}}var bi,kc,yi,_c,lh,Kr,On,hh,dh,Uf,Ff,Nf,xi,Mf,p1,Vo,d1,m1,h1,gh,y1,x1,zf=E(()=>{"use strict";Um();Tn();ah();fh();mi();Go();$f();bi=BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),kc=BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),yi=BigInt(1),_c=BigInt(2),lh=(e,t)=>(e+t/_c)/t;Kr=Pc(bi,void 0,void 0,{sqrt:mh}),On=ih({a:BigInt(0),b:BigInt(7),Fp:Kr,n:kc,Gx:BigInt("55066263022277343669578718895168534326250603453777594175500187360389116729240"),Gy:BigInt("32670510020758816978083085130507043184471273380659243275938904335757337482424"),h:BigInt(1),lowS:!0,endo:{beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),splitScalar:e=>{let t=kc,r=BigInt("0x3086d221a7d46bcde86c90e49284eb15"),n=-yi*BigInt("0xe4437ed6010e88286f547fa90abfe4c3"),o=BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),s=r,i=BigInt("0x100000000000000000000000000000000"),a=lh(s*e,t),c=lh(-n*e,t),u=Ce(e-a*r-c*o,t),f=Ce(-a*n-c*s,t),p=u>i,l=f>i;if(p&&(u=t-u),l&&(f=t-f),u>i||f>i)throw new Error("splitScalar: Endomorphism failed, k="+e);return{k1neg:p,k1:u,k2neg:l,k2:f}}}},Gr),hh=BigInt(0),dh={};Uf=e=>e.toRawBytes(!0).slice(1),Ff=e=>tr(e,32),Nf=e=>Ce(e,bi),xi=e=>Ce(e,kc),Mf=On.ProjectivePoint,p1=(e,t,r)=>Mf.BASE.multiplyAndAddUnsafe(e,t,r);Vo=ut;d1={getPublicKey:f1,sign:l1,verify:bh,utils:{randomPrivateKey:On.utils.randomPrivateKey,lift_x:yh,pointToBytes:Uf,numberToBytesBE:tr,bytesToNumberBE:ut,taggedHash:Bc,mod:Ce}},m1=uh(Kr,[["0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7","0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581","0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262","0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c"],["0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b","0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14","0x0000000000000000000000000000000000000000000000000000000000000001"],["0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c","0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3","0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931","0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84"],["0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b","0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573","0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f","0x0000000000000000000000000000000000000000000000000000000000000001"]].map(e=>e.map(t=>BigInt(t)))),h1=sh(Kr,{A:BigInt("0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533"),B:BigInt("1771"),Z:Kr.create(BigInt("-11"))}),gh=ph(On.ProjectivePoint,e=>{let{x:t,y:r}=h1(Kr.create(e[0]));return m1(t,r)},{DST:"secp256k1_XMD:SHA-256_SSWU_RO_",encodeDST:"secp256k1_XMD:SHA-256_SSWU_NU_",p:Kr.ORDER,m:1,k:128,expand:"xmd",hash:Gr}),y1=gh.hashToCurve,x1=gh.encodeToCurve});var vr,pt,Wo,Ko,Yo,Zo,Xo,Jo,Qo,es,It,Pt,Er=E(()=>{"use strict";go();Y();vr=class extends g{constructor({cause:t,message:r}={}){let n=r?.replace("execution reverted: ","")?.replace("execution reverted","");super(`Execution reverted ${n?`with reason: ${n}`:"for an unknown reason"}.`,{cause:t,name:"ExecutionRevertedError"})}};Object.defineProperty(vr,"code",{enumerable:!0,configurable:!0,writable:!0,value:3});Object.defineProperty(vr,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/execution reverted/});pt=class extends g{constructor({cause:t,maxFeePerGas:r}={}){super(`The fee cap (\`maxFeePerGas\`${r?` = ${Fe(r)} gwei`:""}) cannot be higher than the maximum allowed value (2^256-1).`,{cause:t,name:"FeeCapTooHighError"})}};Object.defineProperty(pt,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/});Wo=class extends g{constructor({cause:t,maxFeePerGas:r}={}){super(`The fee cap (\`maxFeePerGas\`${r?` = ${Fe(r)}`:""} gwei) cannot be lower than the block base fee.`,{cause:t,name:"FeeCapTooLowError"})}};Object.defineProperty(Wo,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/});Ko=class extends g{constructor({cause:t,nonce:r}={}){super(`Nonce provided for the transaction ${r?`(${r}) `:""}is higher than the next one expected.`,{cause:t,name:"NonceTooHighError"})}};Object.defineProperty(Ko,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/nonce too high/});Yo=class extends g{constructor({cause:t,nonce:r}={}){super([`Nonce provided for the transaction ${r?`(${r}) `:""}is lower than the current nonce of the account.`,"Try increasing the nonce or find the latest nonce with `getTransactionCount`."].join(` +`),{cause:t,name:"NonceTooLowError"})}};Object.defineProperty(Yo,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/nonce too low|transaction already imported|already known/});Zo=class extends g{constructor({cause:t,nonce:r}={}){super(`Nonce provided for the transaction ${r?`(${r}) `:""}exceeds the maximum allowed nonce.`,{cause:t,name:"NonceMaxValueError"})}};Object.defineProperty(Zo,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/nonce has max value/});Xo=class extends g{constructor({cause:t}={}){super(["The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account."].join(` +`),{cause:t,metaMessages:["This error could arise when the account does not have enough funds to:"," - pay for the total gas fee,"," - pay for the value to send."," ","The cost of the transaction is calculated as `gas * gas fee + value`, where:"," - `gas` is the amount of gas needed for transaction to execute,"," - `gas fee` is the gas fee,"," - `value` is the amount of ether to send to the recipient."],name:"InsufficientFundsError"})}};Object.defineProperty(Xo,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/insufficient funds|exceeds transaction sender account balance/});Jo=class extends g{constructor({cause:t,gas:r}={}){super(`The amount of gas ${r?`(${r}) `:""}provided for the transaction exceeds the limit allowed for the block.`,{cause:t,name:"IntrinsicGasTooHighError"})}};Object.defineProperty(Jo,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too high|gas limit reached/});Qo=class extends g{constructor({cause:t,gas:r}={}){super(`The amount of gas ${r?`(${r}) `:""}provided for the transaction is too low.`,{cause:t,name:"IntrinsicGasTooLowError"})}};Object.defineProperty(Qo,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too low/});es=class extends g{constructor({cause:t}){super("The transaction type is not supported for this chain.",{cause:t,name:"TransactionTypeNotSupportedError"})}};Object.defineProperty(es,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/transaction type not valid/});It=class extends g{constructor({cause:t,maxPriorityFeePerGas:r,maxFeePerGas:n}={}){super([`The provided tip (\`maxPriorityFeePerGas\`${r?` = ${Fe(r)} gwei`:""}) cannot be higher than the fee cap (\`maxFeePerGas\`${n?` = ${Fe(n)} gwei`:""}).`].join(` +`),{cause:t,name:"TipAboveFeeCapError"})}};Object.defineProperty(It,"nodeMessage",{enumerable:!0,configurable:!0,writable:!0,value:/max priority fee per gas higher than max fee per gas|tip higher than fee cap/});Pt=class extends g{constructor({cause:t}){super(`An error occurred while executing: ${t?.shortMessage}`,{cause:t,name:"UnknownNodeError"})}}});function Yr(e,t){let r=(e.details||"").toLowerCase(),n=e instanceof g?e.walk(o=>o?.code===vr.code):e;return n instanceof g?new vr({cause:e,message:n.details}):vr.nodeMessage.test(r)?new vr({cause:e,message:e.details}):pt.nodeMessage.test(r)?new pt({cause:e,maxFeePerGas:t?.maxFeePerGas}):Wo.nodeMessage.test(r)?new Wo({cause:e,maxFeePerGas:t?.maxFeePerGas}):Ko.nodeMessage.test(r)?new Ko({cause:e,nonce:t?.nonce}):Yo.nodeMessage.test(r)?new Yo({cause:e,nonce:t?.nonce}):Zo.nodeMessage.test(r)?new Zo({cause:e,nonce:t?.nonce}):Xo.nodeMessage.test(r)?new Xo({cause:e}):Jo.nodeMessage.test(r)?new Jo({cause:e,gas:t?.gas}):Qo.nodeMessage.test(r)?new Qo({cause:e,gas:t?.gas}):es.nodeMessage.test(r)?new es({cause:e}):It.nodeMessage.test(r)?new It({cause:e,maxFeePerGas:t?.maxFeePerGas,maxPriorityFeePerGas:t?.maxPriorityFeePerGas}):new Pt({cause:e})}var gi=E(()=>{"use strict";Y();Er()});function Zr(e,{format:t}){if(!t)return{};let r={};function n(s){let i=Object.keys(s);for(let a of i)a in e&&(r[a]=e[a]),s[a]&&typeof s[a]=="object"&&!Array.isArray(s[a])&&n(s[a])}let o=t(e||{});return n(o),r}var wi=E(()=>{"use strict"});function ts(e,t){return({exclude:r,format:n})=>({exclude:r,format:o=>{let s=t(o);if(r)for(let i of r)delete s[i];return{...s,...n(o)}},type:e})}var Fc=E(()=>{"use strict"});function gt(e){let t={};return typeof e.authorizationList<"u"&&(t.authorizationList=v1(e.authorizationList)),typeof e.accessList<"u"&&(t.accessList=e.accessList),typeof e.blobVersionedHashes<"u"&&(t.blobVersionedHashes=e.blobVersionedHashes),typeof e.blobs<"u"&&(typeof e.blobs[0]!="string"?t.blobs=e.blobs.map(r=>se(r)):t.blobs=e.blobs),typeof e.data<"u"&&(t.data=e.data),typeof e.from<"u"&&(t.from=e.from),typeof e.gas<"u"&&(t.gas=R(e.gas)),typeof e.gasPrice<"u"&&(t.gasPrice=R(e.gasPrice)),typeof e.maxFeePerBlobGas<"u"&&(t.maxFeePerBlobGas=R(e.maxFeePerBlobGas)),typeof e.maxFeePerGas<"u"&&(t.maxFeePerGas=R(e.maxFeePerGas)),typeof e.maxPriorityFeePerGas<"u"&&(t.maxPriorityFeePerGas=R(e.maxPriorityFeePerGas)),typeof e.nonce<"u"&&(t.nonce=R(e.nonce)),typeof e.to<"u"&&(t.to=e.to),typeof e.type<"u"&&(t.type=w1[e.type]),typeof e.value<"u"&&(t.value=R(e.value)),t}function v1(e){return e.map(t=>({address:t.address,r:t.r?R(BigInt(t.r)):t.r,s:t.s?R(BigInt(t.s)):t.s,chainId:R(t.chainId),nonce:R(t.nonce),...typeof t.yParity<"u"?{yParity:R(t.yParity)}:{},...typeof t.v<"u"&&typeof t.yParity>"u"?{v:R(t.v)}:{}}))}var w1,Ph,Xr=E(()=>{"use strict";V();Fc();w1={legacy:"0x0",eip2930:"0x1",eip1559:"0x2",eip4844:"0x3",eip7702:"0x4"};Ph=ts("transactionRequest",gt)});function Ch(e){if(!(!e||e.length===0))return e.reduce((t,{slot:r,value:n})=>{if(r.length!==66)throw new Js({size:r.length,targetSize:66,type:"hex"});if(n.length!==66)throw new Js({size:n.length,targetSize:66,type:"hex"});return t[r]=n,t},{})}function E1(e){let{balance:t,nonce:r,state:n,stateDiff:o,code:s}=e,i={};if(s!==void 0&&(i.code=s),t!==void 0&&(i.balance=R(t)),r!==void 0&&(i.nonce=R(r)),n!==void 0&&(i.state=Ch(n)),o!==void 0){if(i.state)throw new pc;i.stateDiff=Ch(o)}return i}function rs(e){if(!e)return;let t={};for(let{address:r,...n}of e){if(!ie(r,{strict:!1}))throw new fe({address:r});if(t[r])throw new uc({address:r});t[r]=E1(n)}return t}var Oc=E(()=>{"use strict";Mt();za();lf();At();V()});var yC,xC,bC,gC,wC,vC,EC,AC,TC,SC,IC,PC,CC,kC,_C,BC,RC,$C,NC,FC,OC,UC,MC,zC,LC,DC,HC,jC,qC,GC,VC,WC,KC,YC,ZC,XC,JC,QC,e8,t8,r8,n8,o8,s8,i8,a8,c8,u8,p8,f8,l8,d8,m8,h8,y8,x8,b8,g8,w8,v8,E8,A8,T8,S8,I8,P8,C8,k8,_8,B8,R8,$8,N8,F8,O8,U8,M8,z8,L8,D8,H8,j8,q8,G8,V8,W8,K8,Y8,Z8,X8,J8,Q8,ek,tk,rk,Jr,Uc=E(()=>{"use strict";yC=2n**(8n-1n)-1n,xC=2n**(16n-1n)-1n,bC=2n**(24n-1n)-1n,gC=2n**(32n-1n)-1n,wC=2n**(40n-1n)-1n,vC=2n**(48n-1n)-1n,EC=2n**(56n-1n)-1n,AC=2n**(64n-1n)-1n,TC=2n**(72n-1n)-1n,SC=2n**(80n-1n)-1n,IC=2n**(88n-1n)-1n,PC=2n**(96n-1n)-1n,CC=2n**(104n-1n)-1n,kC=2n**(112n-1n)-1n,_C=2n**(120n-1n)-1n,BC=2n**(128n-1n)-1n,RC=2n**(136n-1n)-1n,$C=2n**(144n-1n)-1n,NC=2n**(152n-1n)-1n,FC=2n**(160n-1n)-1n,OC=2n**(168n-1n)-1n,UC=2n**(176n-1n)-1n,MC=2n**(184n-1n)-1n,zC=2n**(192n-1n)-1n,LC=2n**(200n-1n)-1n,DC=2n**(208n-1n)-1n,HC=2n**(216n-1n)-1n,jC=2n**(224n-1n)-1n,qC=2n**(232n-1n)-1n,GC=2n**(240n-1n)-1n,VC=2n**(248n-1n)-1n,WC=2n**(256n-1n)-1n,KC=-(2n**(8n-1n)),YC=-(2n**(16n-1n)),ZC=-(2n**(24n-1n)),XC=-(2n**(32n-1n)),JC=-(2n**(40n-1n)),QC=-(2n**(48n-1n)),e8=-(2n**(56n-1n)),t8=-(2n**(64n-1n)),r8=-(2n**(72n-1n)),n8=-(2n**(80n-1n)),o8=-(2n**(88n-1n)),s8=-(2n**(96n-1n)),i8=-(2n**(104n-1n)),a8=-(2n**(112n-1n)),c8=-(2n**(120n-1n)),u8=-(2n**(128n-1n)),p8=-(2n**(136n-1n)),f8=-(2n**(144n-1n)),l8=-(2n**(152n-1n)),d8=-(2n**(160n-1n)),m8=-(2n**(168n-1n)),h8=-(2n**(176n-1n)),y8=-(2n**(184n-1n)),x8=-(2n**(192n-1n)),b8=-(2n**(200n-1n)),g8=-(2n**(208n-1n)),w8=-(2n**(216n-1n)),v8=-(2n**(224n-1n)),E8=-(2n**(232n-1n)),A8=-(2n**(240n-1n)),T8=-(2n**(248n-1n)),S8=-(2n**(256n-1n)),I8=2n**8n-1n,P8=2n**16n-1n,C8=2n**24n-1n,k8=2n**32n-1n,_8=2n**40n-1n,B8=2n**48n-1n,R8=2n**56n-1n,$8=2n**64n-1n,N8=2n**72n-1n,F8=2n**80n-1n,O8=2n**88n-1n,U8=2n**96n-1n,M8=2n**104n-1n,z8=2n**112n-1n,L8=2n**120n-1n,D8=2n**128n-1n,H8=2n**136n-1n,j8=2n**144n-1n,q8=2n**152n-1n,G8=2n**160n-1n,V8=2n**168n-1n,W8=2n**176n-1n,K8=2n**184n-1n,Y8=2n**192n-1n,Z8=2n**200n-1n,X8=2n**208n-1n,J8=2n**216n-1n,Q8=2n**224n-1n,ek=2n**232n-1n,tk=2n**240n-1n,rk=2n**248n-1n,Jr=2n**256n-1n});function ft(e){let{account:t,gasPrice:r,maxFeePerGas:n,maxPriorityFeePerGas:o,to:s}=e,i=t?Z(t):void 0;if(i&&!ie(i.address))throw new fe({address:i.address});if(s&&!ie(s))throw new fe({address:s});if(typeof r<"u"&&(typeof n<"u"||typeof o<"u"))throw new fc;if(n&&n>Jr)throw new pt({maxFeePerGas:n});if(o&&n&&o>n)throw new It({maxFeePerGas:n,maxPriorityFeePerGas:o})}var Qr=E(()=>{"use strict";Pe();Uc();Mt();Er();zt();At()});function rr(e,t){if(!ie(e,{strict:!1}))throw new fe({address:e});if(!ie(t,{strict:!1}))throw new fe({address:t});return e.toLowerCase()===t.toLowerCase()}var ps=E(()=>{"use strict";Mt();At()});function lt(e){let{abi:t,args:r,functionName:n,data:o}=e,s=t[0];if(n){let a=ct({abi:t,args:r,name:n});if(!a)throw new $t(n,{docsPath:jf});s=a}if(s.type!=="function")throw new $t(void 0,{docsPath:jf});if(!s.outputs)throw new fo(s.name,{docsPath:jf});let i=mr(s.outputs,o);if(i&&i.length>1)return i;if(i&&i.length===1)return i[0]}var jf,rn=E(()=>{"use strict";Ae();ci();Mr();jf="/docs/contract/decodeFunctionResult"});var Ei,Yc,zh,Zc,Lh,qf,Gf,Vf,nn=E(()=>{"use strict";Ei=[{inputs:[{components:[{name:"target",type:"address"},{name:"allowFailure",type:"bool"},{name:"callData",type:"bytes"}],name:"calls",type:"tuple[]"}],name:"aggregate3",outputs:[{components:[{name:"success",type:"bool"},{name:"returnData",type:"bytes"}],name:"returnData",type:"tuple[]"}],stateMutability:"view",type:"function"}],Yc=[{name:"query",type:"function",stateMutability:"view",inputs:[{type:"tuple[]",name:"queries",components:[{type:"address",name:"sender"},{type:"string[]",name:"urls"},{type:"bytes",name:"data"}]}],outputs:[{type:"bool[]",name:"failures"},{type:"bytes[]",name:"responses"}]},{name:"HttpError",type:"error",inputs:[{type:"uint16",name:"status"},{type:"string",name:"message"}]}],zh=[{inputs:[],name:"ResolverNotFound",type:"error"},{inputs:[],name:"ResolverWildcardNotSupported",type:"error"},{inputs:[],name:"ResolverNotContract",type:"error"},{inputs:[{name:"returnData",type:"bytes"}],name:"ResolverError",type:"error"},{inputs:[{components:[{name:"status",type:"uint16"},{name:"message",type:"string"}],name:"errors",type:"tuple[]"}],name:"HttpError",type:"error"}],Zc=[...zh,{name:"resolve",type:"function",stateMutability:"view",inputs:[{name:"name",type:"bytes"},{name:"data",type:"bytes"}],outputs:[{name:"",type:"bytes"},{name:"address",type:"address"}]},{name:"resolve",type:"function",stateMutability:"view",inputs:[{name:"name",type:"bytes"},{name:"data",type:"bytes"},{name:"gateways",type:"string[]"}],outputs:[{name:"",type:"bytes"},{name:"address",type:"address"}]}],Lh=[...zh,{name:"reverse",type:"function",stateMutability:"view",inputs:[{type:"bytes",name:"reverseName"}],outputs:[{type:"string",name:"resolvedName"},{type:"address",name:"resolvedAddress"},{type:"address",name:"reverseResolver"},{type:"address",name:"resolver"}]},{name:"reverse",type:"function",stateMutability:"view",inputs:[{type:"bytes",name:"reverseName"},{type:"string[]",name:"gateways"}],outputs:[{type:"string",name:"resolvedName"},{type:"address",name:"resolvedAddress"},{type:"address",name:"reverseResolver"},{type:"address",name:"resolver"}]}],qf=[{name:"text",type:"function",stateMutability:"view",inputs:[{name:"name",type:"bytes32"},{name:"key",type:"string"}],outputs:[{name:"",type:"string"}]}],Gf=[{name:"addr",type:"function",stateMutability:"view",inputs:[{name:"name",type:"bytes32"}],outputs:[{name:"",type:"address"}]},{name:"addr",type:"function",stateMutability:"view",inputs:[{name:"name",type:"bytes32"},{name:"coinType",type:"uint256"}],outputs:[{name:"",type:"bytes"}]}],Vf=[{inputs:[{name:"_signer",type:"address"},{name:"_hash",type:"bytes32"},{name:"_signature",type:"bytes"}],stateMutability:"nonpayable",type:"constructor"},{inputs:[{name:"_signer",type:"address"},{name:"_hash",type:"bytes32"},{name:"_signature",type:"bytes"}],outputs:[{type:"bool"}],stateMutability:"nonpayable",type:"function",name:"isValidSig"}]});var Dh,Hh=E(()=>{"use strict";Dh="0x82ad56cb"});var Xc,jh,qh,Jc=E(()=>{"use strict";Xc="0x608060405234801561001057600080fd5b5060405161018e38038061018e83398101604081905261002f91610124565b6000808351602085016000f59050803b61004857600080fd5b6000808351602085016000855af16040513d6000823e81610067573d81fd5b3d81f35b634e487b7160e01b600052604160045260246000fd5b600082601f83011261009257600080fd5b81516001600160401b038111156100ab576100ab61006b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156100d9576100d961006b565b6040528181528382016020018510156100f157600080fd5b60005b82811015610110576020818601810151838301820152016100f4565b506000918101602001919091529392505050565b6000806040838503121561013757600080fd5b82516001600160401b0381111561014d57600080fd5b61015985828601610081565b602085015190935090506001600160401b0381111561017757600080fd5b61018385828601610081565b915050925092905056fe",jh="0x608060405234801561001057600080fd5b506040516102c03803806102c083398101604081905261002f916101e6565b836001600160a01b03163b6000036100e457600080836001600160a01b03168360405161005c9190610270565b6000604051808303816000865af19150503d8060008114610099576040519150601f19603f3d011682016040523d82523d6000602084013e61009e565b606091505b50915091508115806100b857506001600160a01b0386163b155b156100e1578060405163101bb98d60e01b81526004016100d8919061028c565b60405180910390fd5b50505b6000808451602086016000885af16040513d6000823e81610103573d81fd5b3d81f35b80516001600160a01b038116811461011e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015457818101518382015260200161013c565b50506000910152565b600082601f83011261016e57600080fd5b81516001600160401b0381111561018757610187610123565b604051601f8201601f19908116603f011681016001600160401b03811182821017156101b5576101b5610123565b6040528181528382016020018510156101cd57600080fd5b6101de826020830160208701610139565b949350505050565b600080600080608085870312156101fc57600080fd5b61020585610107565b60208601519094506001600160401b0381111561022157600080fd5b61022d8782880161015d565b93505061023c60408601610107565b60608601519092506001600160401b0381111561025857600080fd5b6102648782880161015d565b91505092959194509250565b60008251610282818460208701610139565b9190910192915050565b60208152600082518060208401526102ab816040850160208701610139565b601f01601f1916919091016040019291505056fe",qh="0x608060405234801561001057600080fd5b5060405161069438038061069483398101604081905261002f9161051e565b600061003c848484610048565b9050806000526001601ff35b60007f64926492649264926492649264926492649264926492649264926492649264926100748361040c565b036101e7576000606080848060200190518101906100929190610577565b60405192955090935091506000906001600160a01b038516906100b69085906105dd565b6000604051808303816000865af19150503d80600081146100f3576040519150601f19603f3d011682016040523d82523d6000602084013e6100f8565b606091505b50509050876001600160a01b03163b60000361016057806101605760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90610190908b9087906004016105f9565b602060405180830381865afa1580156101ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d19190610633565b6001600160e01b03191614945050505050610405565b6001600160a01b0384163b1561027a57604051630b135d3f60e11b808252906001600160a01b03861690631626ba7e9061022790879087906004016105f9565b602060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102689190610633565b6001600160e01b031916149050610405565b81516041146102df5760405162461bcd60e51b815260206004820152603a602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e6774680000000000006064820152608401610157565b6102e7610425565b5060208201516040808401518451859392600091859190811061030c5761030c61065d565b016020015160f81c9050601b811480159061032b57508060ff16601c14155b1561038c5760405162461bcd60e51b815260206004820152603b602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c756500000000006064820152608401610157565b60408051600081526020810180835289905260ff83169181019190915260608101849052608081018390526001600160a01b0389169060019060a0016020604051602081039080840390855afa1580156103ea573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149450505050505b9392505050565b600060208251101561041d57600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b038116811461045857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561048c578181015183820152602001610474565b50506000910152565b600082601f8301126104a657600080fd5b81516001600160401b038111156104bf576104bf61045b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104ed576104ed61045b565b60405281815283820160200185101561050557600080fd5b610516826020830160208701610471565b949350505050565b60008060006060848603121561053357600080fd5b835161053e81610443565b6020850151604086015191945092506001600160401b0381111561056157600080fd5b61056d86828701610495565b9150509250925092565b60008060006060848603121561058c57600080fd5b835161059781610443565b60208501519093506001600160401b038111156105b357600080fd5b6105bf86828701610495565b604086015190935090506001600160401b0381111561056157600080fd5b600082516105ef818460208701610471565b9190910192915050565b828152604060208201526000825180604084015261061e816060850160208701610471565b601f01601f1916919091016060019392505050565b60006020828403121561064557600080fd5b81516001600160e01b03198116811461040557600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572"});var Mn,Qc,eu,Ai,Ar,ms=E(()=>{"use strict";Y();Mn=class extends g{constructor({blockNumber:t,chain:r,contract:n}){super(`Chain "${r.name}" does not support contract "${n.name}".`,{metaMessages:["This could be due to any of the following:",...t&&n.blockCreated&&n.blockCreated>t?[`- The contract "${n.name}" was not deployed until block ${n.blockCreated} (current block ${t}).`]:[`- The chain does not have the contract "${n.name}" configured.`]],name:"ChainDoesNotSupportContract"})}},Qc=class extends g{constructor({chain:t,currentChainId:r}){super(`The current chain of the wallet (id: ${r}) does not match the target chain for the transaction (id: ${t.id} \u2013 ${t.name}).`,{metaMessages:[`Current Chain ID: ${r}`,`Expected Chain ID: ${t.id} \u2013 ${t.name}`],name:"ChainMismatchError"})}},eu=class extends g{constructor(){super(["No chain was provided to the request.","Please provide a chain with the `chain` argument on the Action, or by supplying a `chain` to WalletClient."].join(` +`),{name:"ChainNotFoundError"})}},Ai=class extends g{constructor(){super("No chain was provided to the Client.",{name:"ClientChainNotConfiguredError"})}},Ar=class extends g{constructor({chainId:t}){super(typeof t=="number"?`Chain ID "${t}" is invalid.`:"Chain ID is invalid.",{name:"InvalidChainIdError"})}}});function zn(e){let{abi:t,args:r,bytecode:n}=e;if(!r||r.length===0)return n;let o=t.find(i=>"type"in i&&i.type==="constructor");if(!o)throw new Pa({docsPath:Wf});if(!("inputs"in o))throw new Ws({docsPath:Wf});if(!o.inputs||o.inputs.length===0)throw new Ws({docsPath:Wf});let s=We(o.inputs,r);return _e([n,s])}var Wf,tu=E(()=>{"use strict";Ae();at();Yt();Wf="/docs/contract/encodeDeployData"});function kt({blockNumber:e,chain:t,contract:r}){let n=t?.contracts?.[r];if(!n)throw new Mn({chain:t,contract:{name:r}});if(e&&n.blockCreated&&n.blockCreated>e)throw new Mn({blockNumber:e,chain:t,contract:{name:r,blockCreated:n.blockCreated}});return n.address}var Ln=E(()=>{"use strict";ms()});function ru(e,{docsPath:t,...r}){let n=(()=>{let o=Yr(e,r);return o instanceof Pt?e:o})();return new Eo(n,{docsPath:t,...r})}var Kf=E(()=>{"use strict";Lr();Er();gi()});function hs(){let e=()=>{},t=()=>{};return{promise:new Promise((n,o)=>{e=n,t=o}),resolve:e,reject:t}}var nu=E(()=>{"use strict"});function ou({fn:e,id:t,shouldSplitBatch:r,wait:n=0,sort:o}){let s=async()=>{let f=c();i();let p=f.map(({args:l})=>l);p.length!==0&&e(p).then(l=>{o&&Array.isArray(l)&&l.sort(o);for(let d=0;d{for(let d=0;dYf.delete(t),a=()=>c().map(({args:f})=>f),c=()=>Yf.get(t)||[],u=f=>Yf.set(t,[...c(),f]);return{flush:i,async schedule(f){let{promise:p,resolve:l,reject:d}=hs();return r?.([...a(),f])&&s(),c().length>0?(u({args:f,resolve:l,reject:d}),p):(u({args:f,resolve:l,reject:d}),setTimeout(s,n),p)}}}var Yf,Zf=E(()=>{"use strict";nu();Yf=new Map});var su,iu,au,Gh=E(()=>{"use strict";Xe();Y();xc();su=class extends g{constructor({callbackSelector:t,cause:r,data:n,extraData:o,sender:s,urls:i}){super(r.shortMessage||"An error occurred while fetching for an offchain result.",{cause:r,metaMessages:[...r.metaMessages||[],r.metaMessages?.length?"":[],"Offchain Gateway Call:",i&&[" Gateway URL(s):",...i.map(a=>` ${Pn(a)}`)],` Sender: ${s}`,` Data: ${n}`,` Callback selector: ${t}`,` Extra data: ${o}`].flat(),name:"OffchainLookupError"})}},iu=class extends g{constructor({result:t,url:r}){super("Offchain gateway response is malformed. Response data must be a hex value.",{metaMessages:[`Gateway URL: ${Pn(r)}`,`Response: ${ee(t)}`],name:"OffchainLookupResponseMalformedError"})}},au=class extends g{constructor({sender:t,to:r}){super("Reverted sender address does not match target contract address (`to`).",{metaMessages:[`Contract address: ${r}`,`OffchainLookup sender address: ${t}`],name:"OffchainLookupSenderMismatchError"})}}});function Vh(e){let{abi:t,data:r}=e,n=Tt(r,0,4),o=t.find(s=>s.type==="function"&&n===Zt(Re(s)));if(!o)throw new $a(n,{docsPath:"/docs/contract/decodeFunctionData"});return{functionName:o.name,args:"inputs"in o&&o.inputs&&o.inputs.length>0?mr(o.inputs,Tt(r,4)):void 0}}var Wh=E(()=>{"use strict";Ae();Ur();ho();ci();ur()});function Jf(e){let{abi:t,errorName:r,args:n}=e,o=t[0];if(r){let c=ct({abi:t,args:n,name:r});if(!c)throw new Ks(r,{docsPath:Xf});o=c}if(o.type!=="error")throw new Ks(void 0,{docsPath:Xf});let s=Re(o),i=Zt(s),a="0x";if(n&&n.length>0){if(!o.inputs)throw new Ba(o.name,{docsPath:Xf});a=We(o.inputs,n)}return _e([i,a])}var Xf,Kh=E(()=>{"use strict";Ae();at();ho();Yt();ur();Mr();Xf="/docs/contract/encodeErrorResult"});function Yh(e){let{abi:t,functionName:r,result:n}=e,o=t[0];if(r){let i=ct({abi:t,name:r});if(!i)throw new $t(r,{docsPath:Qf});o=i}if(o.type!=="function")throw new $t(void 0,{docsPath:Qf});if(!o.outputs)throw new fo(o.name,{docsPath:Qf});let s=(()=>{if(o.outputs.length===0)return[];if(o.outputs.length===1)return[n];if(Array.isArray(n))return n;throw new lo(n)})();return We(o.outputs,s)}var Qf,Zh=E(()=>{"use strict";Ae();Yt();Mr();Qf="/docs/contract/encodeFunctionResult"});async function Xh(e){let{data:t,ccipRequest:r}=e,{args:[n]}=Vh({abi:Yc,data:t}),o=[],s=[];return await Promise.all(n.map(async(i,a)=>{try{s[a]=await r(i),o[a]=!1}catch(c){o[a]=!0,s[a]=C1(c)}})),Yh({abi:Yc,functionName:"query",result:[o,s]})}function C1(e){return e.name==="HttpRequestError"&&e.status?Jf({abi:Yc,errorName:"HttpError",args:[e.status,e.shortMessage]}):Jf({abi:[rc],errorName:"Error",args:["shortMessage"in e?e.shortMessage:e.message]})}var ys,cu=E(()=>{"use strict";nn();si();Wh();Kh();Zh();ys="x-batch-gateway:true"});var ey={};Ip(ey,{ccipRequest:()=>Qh,offchainLookup:()=>_1,offchainLookupAbiItem:()=>Jh,offchainLookupSignature:()=>k1});async function _1(e,{blockNumber:t,blockTag:r,data:n,to:o}){let{args:s}=sc({data:n,abi:[Jh]}),[i,a,c,u,f]=s,{ccipRead:p}=e,l=p&&typeof p?.request=="function"?p.request:Qh;try{if(!rr(o,i))throw new au({sender:i,to:o});let d=a.includes(ys)?await Xh({data:c,ccipRequest:l}):await l({data:c,sender:i,urls:a}),{data:y}=await nr(e,{blockNumber:t,blockTag:r,data:rt([u,We([{type:"bytes"},{type:"bytes"}],[d,f])]),to:o});return y}catch(d){throw new su({callbackSelector:u,cause:d,data:n,extraData:f,sender:i,urls:a})}}async function Qh({data:e,sender:t,urls:r}){let n=new Error("An unknown error occurred.");for(let o=0;o{"use strict";xs();Gh();kn();uf();Yt();ps();at();Rt();cu();Xe();k1="0x556f1830",Jh={name:"OffchainLookup",type:"error",inputs:[{name:"sender",type:"address"},{name:"urls",type:"string[]"},{name:"callData",type:"bytes"},{name:"callbackFunction",type:"bytes4"},{name:"extraData",type:"bytes"}]}});async function nr(e,t){let{account:r=e.account,batch:n=!!e.batch?.multicall,blockNumber:o,blockTag:s="latest",accessList:i,blobs:a,code:c,data:u,factory:f,factoryData:p,gas:l,gasPrice:d,maxFeePerBlobGas:y,maxFeePerGas:x,maxPriorityFeePerGas:m,nonce:h,to:b,value:v,stateOverride:A,...k}=t,S=r?Z(r):void 0;if(c&&(f||p))throw new g("Cannot provide both `code` & `factory`/`factoryData` as parameters.");if(c&&b)throw new g("Cannot provide both `code` & `to` as parameters.");let T=c&&u,_=f&&p&&b&&u,C=T||_,D=T?$1({code:c,data:u}):_?N1({data:u,factory:f,factoryData:p,to:b}):u;try{ft(t);let L=(o?R(o):void 0)||s,ae=rs(A),B=e.chain?.formatters?.transactionRequest?.format,N=(B||gt)({...Zr(k,{format:B}),from:S?.address,accessList:i,blobs:a,data:D,gas:l,gasPrice:d,maxFeePerBlobGas:y,maxFeePerGas:x,maxPriorityFeePerGas:m,nonce:h,to:C?void 0:b,value:v});if(n&&B1({request:N})&&!ae)try{return await R1(e,{...N,blockNumber:o,blockTag:s})}catch(j){if(!(j instanceof Ai)&&!(j instanceof Mn))throw j}let G=await e.request({method:"eth_call",params:ae?[N,L,ae]:[N,L]});return G==="0x"?{data:void 0}:{data:G}}catch(z){let L=F1(z),{offchainLookup:ae,offchainLookupSignature:B}=await Promise.resolve().then(()=>(ty(),ey));if(e.ccipRead!==!1&&L?.slice(0,10)===B&&b)return{data:await ae(e,{data:L,to:b})};throw C&&L?.slice(0,10)==="0x101bb98d"?new wc({factory:f}):ru(z,{...t,account:S,chain:e.chain})}}function B1({request:e}){let{data:t,to:r,...n}=e;return!(!t||t.startsWith(Dh)||!r||Object.values(n).filter(o=>typeof o<"u").length>0)}async function R1(e,t){let{batchSize:r=1024,wait:n=0}=typeof e.batch?.multicall=="object"?e.batch.multicall:{},{blockNumber:o,blockTag:s="latest",data:i,multicallAddress:a,to:c}=t,u=a;if(!u){if(!e.chain)throw new Ai;u=kt({blockNumber:o,chain:e.chain,contract:"multicall3"})}let p=(o?R(o):void 0)||s,{schedule:l}=ou({id:`${e.uid}.${p}`,wait:n,shouldSplitBatch(x){return x.reduce((h,{data:b})=>h+(b.length-2),0)>r*2},fn:async x=>{let m=x.map(v=>({allowFailure:!0,callData:v.data,target:v.to})),h=be({abi:Ei,args:[m],functionName:"aggregate3"}),b=await e.request({method:"eth_call",params:[{data:h,to:u},p]});return lt({abi:Ei,args:[m],functionName:"aggregate3",data:b||"0x"})}}),[{returnData:d,success:y}]=await l({data:i,to:c});if(!y)throw new Qt({data:d});return d==="0x"?{data:void 0}:{data:d}}function $1(e){let{code:t,data:r}=e;return zn({abi:Aa(["constructor(bytes, bytes)"]),bytecode:Xc,args:[t,r]})}function N1(e){let{data:t,factory:r,factoryData:n,to:o}=e;return zn({abi:Aa(["constructor(address, bytes, address, bytes)"]),bytecode:jh,args:[o,t,r,n]})}function F1(e){if(!(e instanceof g))return;let t=e.walk();return typeof t?.data=="object"?t.data?.data:t.data}var xs=E(()=>{"use strict";Sa();Pe();nn();Hh();Jc();Y();ms();Lr();rn();tu();ht();Ln();V();Kf();wi();Xr();Zf();Oc();Qr()});var E0,A0=E(()=>{"use strict";E0="1.0.8"});var Me,Bs=E(()=>{"use strict";A0();Me=class e extends Error{constructor(t,r={}){let n=r.cause instanceof e?r.cause.details:r.cause?.message?r.cause.message:r.details,o=r.cause instanceof e&&r.cause.docsPath||r.docsPath,s=[t||"An error occurred.","",...r.metaMessages?[...r.metaMessages,""]:[],...o?[`Docs: https://abitype.dev${o}`]:[],...n?[`Details: ${n}`]:[],`Version: abitype@${E0}`].join(` +`);super(s),Object.defineProperty(this,"details",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"docsPath",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"metaMessages",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"shortMessage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"AbiTypeError"}),r.cause&&(this.cause=r.cause),this.details=n,this.docsPath=o,this.metaMessages=r.metaMessages,this.shortMessage=t}}});function Ht(e,t){return e.exec(t)?.groups}var Rl,$l,lp,dp=E(()=>{"use strict";Rl=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,$l=/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/,lp=/^\(.+?\).*?$/});function S0(e){return T0.test(e)}function I0(e){return Ht(T0,e)}function C0(e){return P0.test(e)}function k0(e){return Ht(P0,e)}function B0(e){return _0.test(e)}function R0(e){return Ht(_0,e)}function mp(e){return $0.test(e)}function N0(e){return Ht($0,e)}function O0(e){return F0.test(e)}function U0(e){return Ht(F0,e)}function z0(e){return M0.test(e)}function L0(e){return Ht(M0,e)}function D0(e){return uv.test(e)}var T0,P0,_0,$0,F0,M0,uv,H0,hp,yp=E(()=>{"use strict";dp();T0=/^error (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;P0=/^event (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;_0=/^function (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)(?: (?external|public{1}))?(?: (?pure|view|nonpayable|payable{1}))?(?: returns\s?\((?.*?)\))?$/;$0=/^struct (?[a-zA-Z$_][a-zA-Z0-9$_]*) \{(?.*?)\}$/;F0=/^constructor\((?.*?)\)(?:\s(?payable{1}))?$/;M0=/^fallback\(\) external(?:\s(?payable{1}))?$/;uv=/^receive\(\) external payable$/;H0=new Set(["indexed"]),hp=new Set(["calldata","memory","storage"])});var Fi,xp,Nl=E(()=>{"use strict";Bs();Fi=class extends Me{constructor({type:t}){super("Unknown type.",{metaMessages:[`Type "${t}" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"UnknownTypeError"})}},xp=class extends Me{constructor({type:t}){super("Unknown type.",{metaMessages:[`Type "${t}" is not a valid ABI type.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"UnknownSolidityTypeError"})}}});var Oi,Ui,Mi,zi,Li,Fl=E(()=>{"use strict";Bs();Oi=class extends Me{constructor({param:t}){super("Invalid ABI parameter.",{details:t}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidParameterError"})}},Ui=class extends Me{constructor({param:t,name:r}){super("Invalid ABI parameter.",{details:t,metaMessages:[`"${r}" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"SolidityProtectedKeywordError"})}},Mi=class extends Me{constructor({param:t,type:r,modifier:n}){super("Invalid ABI parameter.",{details:t,metaMessages:[`Modifier "${n}" not allowed${r?` in "${r}" type`:""}.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidModifierError"})}},zi=class extends Me{constructor({param:t,type:r,modifier:n}){super("Invalid ABI parameter.",{details:t,metaMessages:[`Modifier "${n}" not allowed${r?` in "${r}" type`:""}.`,`Data location can only be specified for array, struct, or mapping types, but "${n}" was given.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidFunctionModifierError"})}},Li=class extends Me{constructor({abiParameter:t}){super("Invalid ABI parameter.",{details:JSON.stringify(t,null,2),metaMessages:["ABI parameter type is invalid."]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidAbiTypeParameterError"})}}});var jt,Di,Hi,Ol=E(()=>{"use strict";Bs();jt=class extends Me{constructor({signature:t,type:r}){super(`Invalid ${r} signature.`,{details:t}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidSignatureError"})}},Di=class extends Me{constructor({signature:t}){super("Unknown signature.",{details:t}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"UnknownSignatureError"})}},Hi=class extends Me{constructor({signature:t}){super("Invalid struct signature.",{details:t,metaMessages:["No properties exist."]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidStructSignatureError"})}}});var ji,j0=E(()=>{"use strict";Bs();ji=class extends Me{constructor({type:t}){super("Circular reference detected.",{metaMessages:[`Struct "${t}" is a circular reference.`]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"CircularReferenceError"})}}});var qi,q0=E(()=>{"use strict";Bs();qi=class extends Me{constructor({current:t,depth:r}){super("Unbalanced parentheses.",{metaMessages:[`"${t.trim()}" has too many ${r>0?"opening":"closing"} parentheses.`],details:`Depth "${r}"`}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"InvalidParenthesisError"})}}});function G0(e,t,r){let n="";if(r)for(let o of Object.entries(r)){if(!o)continue;let s="";for(let i of o[1])s+=`[${i.type}${i.name?`:${i.name}`:""}]`;n+=`(${o[0]}{${s}})`}return t?`${t}:${e}${n}`:e}var bp,V0=E(()=>{"use strict";bp=new Map([["address",{type:"address"}],["bool",{type:"bool"}],["bytes",{type:"bytes"}],["bytes32",{type:"bytes32"}],["int",{type:"int256"}],["int256",{type:"int256"}],["string",{type:"string"}],["uint",{type:"uint256"}],["uint8",{type:"uint8"}],["uint16",{type:"uint16"}],["uint24",{type:"uint24"}],["uint32",{type:"uint32"}],["uint64",{type:"uint64"}],["uint96",{type:"uint96"}],["uint112",{type:"uint112"}],["uint160",{type:"uint160"}],["uint192",{type:"uint192"}],["uint256",{type:"uint256"}],["address owner",{type:"address",name:"owner"}],["address to",{type:"address",name:"to"}],["bool approved",{type:"bool",name:"approved"}],["bytes _data",{type:"bytes",name:"_data"}],["bytes data",{type:"bytes",name:"data"}],["bytes signature",{type:"bytes",name:"signature"}],["bytes32 hash",{type:"bytes32",name:"hash"}],["bytes32 r",{type:"bytes32",name:"r"}],["bytes32 root",{type:"bytes32",name:"root"}],["bytes32 s",{type:"bytes32",name:"s"}],["string name",{type:"string",name:"name"}],["string symbol",{type:"string",name:"symbol"}],["string tokenURI",{type:"string",name:"tokenURI"}],["uint tokenId",{type:"uint256",name:"tokenId"}],["uint8 v",{type:"uint8",name:"v"}],["uint256 balance",{type:"uint256",name:"balance"}],["uint256 tokenId",{type:"uint256",name:"tokenId"}],["uint256 value",{type:"uint256",name:"value"}],["event:address indexed from",{type:"address",name:"from",indexed:!0}],["event:address indexed to",{type:"address",name:"to",indexed:!0}],["event:uint indexed tokenId",{type:"uint256",name:"tokenId",indexed:!0}],["event:uint256 indexed tokenId",{type:"uint256",name:"tokenId",indexed:!0}]])});function W0(e,t={}){if(B0(e))return pv(e,t);if(C0(e))return fv(e,t);if(S0(e))return lv(e,t);if(O0(e))return dv(e,t);if(z0(e))return mv(e);if(D0(e))return{type:"receive",stateMutability:"payable"};throw new Di({signature:e})}function pv(e,t={}){let r=R0(e);if(!r)throw new jt({signature:e,type:"function"});let n=qt(r.parameters),o=[],s=n.length;for(let a=0;a{"use strict";dp();Nl();Fl();Ol();q0();V0();yp();hv=/^(?[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,yv=/^\((?.+?)\)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,xv=/^u?int$/;bv=/^(?:after|alias|anonymous|apply|auto|byte|calldata|case|catch|constant|copyof|default|defined|error|event|external|false|final|function|immutable|implements|in|indexed|inline|internal|let|mapping|match|memory|mutable|null|of|override|partial|private|promise|public|pure|reference|relocatable|return|returns|sizeof|static|storage|struct|super|supports|switch|this|true|try|typedef|typeof|var|view|virtual)$/});function K0(e){let t={},r=e.length;for(let i=0;i{"use strict";dp();Nl();Fl();Ol();j0();yp();Ml();vv=/^(?[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?$/});function Rs(e){let t=K0(e),r=[],n=e.length;for(let o=0;o{"use strict";yp();Z0();Ml()});var J0=E(()=>{"use strict";X0()});var Q0,eb=E(()=>{"use strict";Q0={gwei:9,wei:18}});function tb(e,t){let r=e.toString(),n=r.startsWith("-");n&&(r=r.slice(1)),r=r.padStart(t,"0");let[o,s]=[r.slice(0,r.length-t),r.slice(r.length-t)];return s=s.replace(/(0+)$/,""),`${n?"-":""}${o||"0"}${s?`.${s}`:""}`}var rb=E(()=>{"use strict"});function gp(e,t="wei"){return tb(e,Q0[t])}var nb=E(()=>{"use strict";eb();rb()});var Mv={};Ip(Mv,{GooddollarLiquidityWidget:()=>oe});var Ji=globalThis,Qi=Ji.ShadowRoot&&(Ji.ShadyCSS===void 0||Ji.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Pp=Symbol(),ql=new WeakMap,Fs=class{constructor(t,r,n){if(this._$cssResult$=!0,n!==Pp)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=r}get styleSheet(){let t=this.o,r=this.t;if(Qi&&t===void 0){let n=r!==void 0&&r.length===1;n&&(t=ql.get(r)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),n&&ql.set(r,t))}return t}toString(){return this.cssText}},Gl=e=>new Fs(typeof e=="string"?e:e+"",void 0,Pp),Ge=(e,...t)=>{let r=e.length===1?e[0]:t.reduce((n,o,s)=>n+(i=>{if(i._$cssResult$===!0)return i.cssText;if(typeof i=="number")return i;throw Error("Value passed to 'css' function must be a 'css' function result: "+i+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(o)+e[s+1],e[0]);return new Fs(r,e,Pp)},Vl=(e,t)=>{if(Qi)e.adoptedStyleSheets=t.map(r=>r instanceof CSSStyleSheet?r:r.styleSheet);else for(let r of t){let n=document.createElement("style"),o=Ji.litNonce;o!==void 0&&n.setAttribute("nonce",o),n.textContent=r.cssText,e.appendChild(n)}},Cp=Qi?e=>e:e=>e instanceof CSSStyleSheet?(t=>{let r="";for(let n of t.cssRules)r+=n.cssText;return Gl(r)})(e):e;var{is:Sb,defineProperty:Ib,getOwnPropertyDescriptor:Pb,getOwnPropertyNames:Cb,getOwnPropertySymbols:kb,getPrototypeOf:_b}=Object,ea=globalThis,Wl=ea.trustedTypes,Bb=Wl?Wl.emptyScript:"",Rb=ea.reactiveElementPolyfillSupport,Os=(e,t)=>e,Us={toAttribute(e,t){switch(t){case Boolean:e=e?Bb:null;break;case Object:case Array:e=e==null?e:JSON.stringify(e)}return e},fromAttribute(e,t){let r=e;switch(t){case Boolean:r=e!==null;break;case Number:r=e===null?null:Number(e);break;case Object:case Array:try{r=JSON.parse(e)}catch{r=null}}return r}},ta=(e,t)=>!Sb(e,t),Kl={attribute:!0,type:String,converter:Us,reflect:!1,useDefault:!1,hasChanged:ta};Symbol.metadata??=Symbol("metadata"),ea.litPropertyMetadata??=new WeakMap;var cr=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,r=Kl){if(r.state&&(r.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((r=Object.create(r)).wrapped=!0),this.elementProperties.set(t,r),!r.noAccessor){let n=Symbol(),o=this.getPropertyDescriptor(t,n,r);o!==void 0&&Ib(this.prototype,t,o)}}static getPropertyDescriptor(t,r,n){let{get:o,set:s}=Pb(this.prototype,t)??{get(){return this[r]},set(i){this[r]=i}};return{get:o,set(i){let a=o?.call(this);s?.call(this,i),this.requestUpdate(t,a,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??Kl}static _$Ei(){if(this.hasOwnProperty(Os("elementProperties")))return;let t=_b(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(Os("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(Os("properties"))){let r=this.properties,n=[...Cb(r),...kb(r)];for(let o of n)this.createProperty(o,r[o])}let t=this[Symbol.metadata];if(t!==null){let r=litPropertyMetadata.get(t);if(r!==void 0)for(let[n,o]of r)this.elementProperties.set(n,o)}this._$Eh=new Map;for(let[r,n]of this.elementProperties){let o=this._$Eu(r,n);o!==void 0&&this._$Eh.set(o,r)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){let r=[];if(Array.isArray(t)){let n=new Set(t.flat(1/0).reverse());for(let o of n)r.unshift(Cp(o))}else t!==void 0&&r.push(Cp(t));return r}static _$Eu(t,r){let n=r.attribute;return n===!1?void 0:typeof n=="string"?n:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){let t=new Map,r=this.constructor.elementProperties;for(let n of r.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){let t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Vl(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,r,n){this._$AK(t,n)}_$ET(t,r){let n=this.constructor.elementProperties.get(t),o=this.constructor._$Eu(t,n);if(o!==void 0&&n.reflect===!0){let s=(n.converter?.toAttribute!==void 0?n.converter:Us).toAttribute(r,n.type);this._$Em=t,s==null?this.removeAttribute(o):this.setAttribute(o,s),this._$Em=null}}_$AK(t,r){let n=this.constructor,o=n._$Eh.get(t);if(o!==void 0&&this._$Em!==o){let s=n.getPropertyOptions(o),i=typeof s.converter=="function"?{fromAttribute:s.converter}:s.converter?.fromAttribute!==void 0?s.converter:Us;this._$Em=o;let a=i.fromAttribute(r,s.type);this[o]=a??this._$Ej?.get(o)??a,this._$Em=null}}requestUpdate(t,r,n){if(t!==void 0){let o=this.constructor,s=this[t];if(n??=o.getPropertyOptions(t),!((n.hasChanged??ta)(s,r)||n.useDefault&&n.reflect&&s===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,n))))return;this.C(t,r,n)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,r,{useDefault:n,reflect:o,wrapped:s},i){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,i??r??this[t]),s!==!0||i!==void 0)||(this._$AL.has(t)||(this.hasUpdated||n||(r=void 0),this._$AL.set(t,r)),o===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(r){Promise.reject(r)}let t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[o,s]of this._$Ep)this[o]=s;this._$Ep=void 0}let n=this.constructor.elementProperties;if(n.size>0)for(let[o,s]of n){let{wrapped:i}=s,a=this[o];i!==!0||this._$AL.has(o)||a===void 0||this.C(o,void 0,s,a)}}let t=!1,r=this._$AL;try{t=this.shouldUpdate(r),t?(this.willUpdate(r),this._$EO?.forEach(n=>n.hostUpdate?.()),this.update(r)):this._$EM()}catch(n){throw t=!1,this._$EM(),n}t&&this._$AE(r)}willUpdate(t){}_$AE(t){this._$EO?.forEach(r=>r.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(r=>this._$ET(r,this[r])),this._$EM()}updated(t){}firstUpdated(t){}};cr.elementStyles=[],cr.shadowRootOptions={mode:"open"},cr[Os("elementProperties")]=new Map,cr[Os("finalized")]=new Map,Rb?.({ReactiveElement:cr}),(ea.reactiveElementVersions??=[]).push("2.1.1");var Fp=globalThis,ra=Fp.trustedTypes,Yl=ra?ra.createPolicy("lit-html",{createHTML:e=>e}):void 0,td="$lit$",kr=`lit$${Math.random().toFixed(9).slice(2)}$`,rd="?"+kr,$b=`<${rd}>`,gn=document,zs=()=>gn.createComment(""),Ls=e=>e===null||typeof e!="object"&&typeof e!="function",Op=Array.isArray,Nb=e=>Op(e)||typeof e?.[Symbol.iterator]=="function",kp=`[ +\f\r]`,Ms=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Zl=/-->/g,Xl=/>/g,xn=RegExp(`>|${kp}(?:([^\\s"'>=/]+)(${kp}*=${kp}*(?:[^ +\f\r"'\`<>=]|("|')|))|$)`,"g"),Jl=/'/g,Ql=/"/g,nd=/^(?:script|style|textarea|title)$/i,Up=e=>(t,...r)=>({_$litType$:e,strings:t,values:r}),K=Up(1),s6=Up(2),i6=Up(3),wn=Symbol.for("lit-noChange"),we=Symbol.for("lit-nothing"),ed=new WeakMap,bn=gn.createTreeWalker(gn,129);function od(e,t){if(!Op(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return Yl!==void 0?Yl.createHTML(t):t}var Fb=(e,t)=>{let r=e.length-1,n=[],o,s=t===2?"":t===3?"":"",i=Ms;for(let a=0;a"?(i=o??Ms,p=-1):f[1]===void 0?p=-2:(p=i.lastIndex-f[2].length,u=f[1],i=f[3]===void 0?xn:f[3]==='"'?Ql:Jl):i===Ql||i===Jl?i=xn:i===Zl||i===Xl?i=Ms:(i=xn,o=void 0);let d=i===xn&&e[a+1].startsWith("/>")?" ":"";s+=i===Ms?c+$b:p>=0?(n.push(u),c.slice(0,p)+td+c.slice(p)+kr+d):c+kr+(p===-2?a:d)}return[od(e,s+(e[r]||"")+(t===2?"":t===3?"":"")),n]},Ds=class e{constructor({strings:t,_$litType$:r},n){let o;this.parts=[];let s=0,i=0,a=t.length-1,c=this.parts,[u,f]=Fb(t,r);if(this.el=e.createElement(u,n),bn.currentNode=this.el.content,r===2||r===3){let p=this.el.content.firstChild;p.replaceWith(...p.childNodes)}for(;(o=bn.nextNode())!==null&&c.length0){o.textContent=ra?ra.emptyScript:"";for(let d=0;d2||n[0]!==""||n[1]!==""?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=we}_$AI(t,r=this,n,o){let s=this.strings,i=!1;if(s===void 0)t=no(this,t,r,0),i=!Ls(t)||t!==this._$AH&&t!==wn,i&&(this._$AH=t);else{let a=t,c,u;for(t=s[0],c=0;c{let n=r?.renderBefore??t,o=n._$litPart$;if(o===void 0){let s=r?.renderBefore??null;n._$litPart$=o=new Hs(t.insertBefore(zs(),s),s,void 0,r??{})}return o._$AI(e),o};var Mp=globalThis,Ee=class extends cr{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){let r=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=sd(r,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return wn}};Ee._$litElement$=!0,Ee.finalized=!0,Mp.litElementHydrateSupport?.({LitElement:Ee});var Ub=Mp.litElementPolyfillSupport;Ub?.({LitElement:Ee});(Mp.litElementVersions??=[]).push("4.2.1");var Ze=e=>(t,r)=>{r!==void 0?r.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};var Mb={attribute:!0,type:String,converter:Us,reflect:!1,hasChanged:ta},zb=(e=Mb,t,r)=>{let{kind:n,metadata:o}=r,s=globalThis.litPropertyMetadata.get(o);if(s===void 0&&globalThis.litPropertyMetadata.set(o,s=new Map),n==="setter"&&((e=Object.create(e)).wrapped=!0),s.set(r.name,e),n==="accessor"){let{name:i}=r;return{set(a){let c=t.get.call(this);t.set.call(this,a),this.requestUpdate(i,c,e)},init(a){return a!==void 0&&this.C(i,void 0,e,a),a}}}if(n==="setter"){let{name:i}=r;return function(a){let c=this[i];t.call(this,a),this.requestUpdate(i,c,e)}}throw Error("Unsupported decorator location: "+n)};function re(e){return(t,r)=>typeof r=="object"?zb(e,t,r):((n,o,s)=>{let i=o.hasOwnProperty(s);return o.constructor.createProperty(s,n),i?Object.getOwnPropertyDescriptor(o,s):void 0})(e,t,r)}function ve(e){return re({...e,state:!0,attribute:!1})}function $(e,t,r){let n=e[t.name];if(typeof n=="function")return n;let o=e[r];return typeof o=="function"?o:s=>t(e,s)}Ae();Y();var Ma=class extends g{constructor(t){super(`Filter type "${t}" is not supported.`,{name:"FilterTypeNotSupportedError"})}};He();Ut();ni();Yt();ur();Mr();var xm="/docs/contract/encodeEventTopics";function Xt(e){let{abi:t,eventName:r,args:n}=e,o=t[0];if(r){let c=ct({abi:t,name:r});if(!c)throw new Ys(r,{docsPath:xm});o=c}if(o.type!=="event")throw new Ys(void 0,{docsPath:xm});let s=Re(o),i=Or(s),a=[];if(n&&"inputs"in o){let c=o.inputs?.filter(f=>"indexed"in f&&f.indexed),u=Array.isArray(n)?n:Object.values(n).length>0?c?.map(f=>n[f.name])??[]:[];u.length>0&&(a=c?.map((f,p)=>Array.isArray(u[p])?u[p].map((l,d)=>bm({param:f,value:u[p][d]})):typeof u[p]<"u"&&u[p]!==null?bm({param:f,value:u[p]}):null)??[])}return[i,...a]}function bm({param:e,value:t}){if(e.type==="string"||e.type==="bytes")return de(Et(t));if(e.type==="tuple"||e.type.match(/^(.*)\[(\d+)?\]$/))throw new Ma(e.type);return We([e],[t])}V();function zr(e,{method:t}){let r={};return e.transport.type==="fallback"&&e.transport.onResponse?.(({method:n,response:o,status:s,transport:i})=>{s==="success"&&t===n&&(r[o]=i.request)}),n=>r[n]||e.request}async function ec(e,t){let{address:r,abi:n,args:o,eventName:s,fromBlock:i,strict:a,toBlock:c}=t,u=zr(e,{method:"eth_newFilter"}),f=s?Xt({abi:n,args:o,eventName:s}):void 0,p=await e.request({method:"eth_newFilter",params:[{address:r,fromBlock:typeof i=="bigint"?R(i):i,toBlock:typeof c=="bigint"?R(c):c,topics:f}]});return{abi:n,args:o,eventName:s,id:p,request:u(p),strict:!!a,type:"event"}}Pe();ht();Ae();Y();Lr();kn();fi();var zg=3;function yt(e,{abi:t,address:r,args:n,docsPath:o,functionName:s,sender:i}){let a=e instanceof Qt?e:e instanceof g?e.walk(y=>"data"in y)||e.walk():{},{code:c,data:u,details:f,message:p,shortMessage:l}=a,d=e instanceof vt?new gc({functionName:s}):[zg,hr.code].includes(c)&&(u||f||p||l)?new Cn({abi:t,data:typeof u=="object"?u.data:u,functionName:s,message:a instanceof Dr?f:l??p}):e;return new bc(d,{abi:t,args:n,contractAddress:r,docsPath:o,functionName:s,sender:i})}Pe();Y();Sn();Ut();function $m(e){let t=de(`0x${e.substring(4)}`).substring(26);return dr(`0x${t}`)}Rt();wt();Ve();V();async function Eh({hash:e,signature:t}){let r=Ie(e)?e:M(e),{secp256k1:n}=await Promise.resolve().then(()=>(zf(),wh));return`0x${(()=>{if(typeof t=="object"&&"r"in t&&"s"in t){let{r:u,s:f,v:p,yParity:l}=t,d=Number(l??p),y=vh(d);return new n.Signature(ge(u),ge(f)).addRecoveryBit(y)}let i=Ie(t)?t:M(t);if(ne(i)!==65)throw new Error("invalid signature length");let a=Te(`0x${i.slice(130)}`),c=vh(a);return n.Signature.fromCompact(i.substring(2,130)).addRecoveryBit(c)})().recoverPublicKey(r.substring(2)).toHex(!1)}`}function vh(e){if(e===0||e===1)return e;if(e===27)return 0;if(e===28)return 1;throw new Error("Invalid yParityOrV value")}async function Rc({hash:e,signature:t}){return $m(await Eh({hash:e,signature:t}))}at();He();V();Y();oc();He();V();function bt(e,t="hex"){let r=Ah(e),n=xo(new Uint8Array(r.length));return r.encode(n),t==="hex"?se(n.bytes):n.bytes}function Ah(e){return Array.isArray(e)?b1(e.map(t=>Ah(t))):g1(e)}function b1(e){let t=e.reduce((o,s)=>o+s.length,0),r=Th(t);return{length:t<=55?1+t:1+r+t,encode(o){t<=55?o.pushByte(192+t):(o.pushByte(247+r),r===1?o.pushUint8(t):r===2?o.pushUint16(t):r===3?o.pushUint24(t):o.pushUint32(t));for(let{encode:s}of e)s(o)}}}function g1(e){let t=typeof e=="string"?Ne(e):e,r=Th(t.length);return{length:t.length===1&&t[0]<128?1:t.length<=55?1+t.length:1+r+t.length,encode(o){t.length===1&&t[0]<128?o.pushBytes(t):t.length<=55?(o.pushByte(128+t.length),o.pushBytes(t)):(o.pushByte(183+r),r===1?o.pushUint8(t.length):r===2?o.pushUint16(t.length):r===3?o.pushUint24(t.length):o.pushUint32(t.length),o.pushBytes(t))}}}function Th(e){if(e<2**8)return 1;if(e<2**16)return 2;if(e<2**24)return 3;if(e<2**32)return 4;throw new g("Length is too large.")}Ut();function Sh(e){let{chainId:t,nonce:r,to:n}=e,o=e.contractAddress??e.address,s=de(_e(["0x05",bt([t?R(t):"0x",o,r?R(r):"0x"])]));return n==="bytes"?Ne(s):s}async function $c(e){let{authorization:t,signature:r}=e;return Rc({hash:Sh(t),signature:r??t})}V();ui();go();Y();zt();var Nc=class extends g{constructor(t,{account:r,docsPath:n,chain:o,data:s,gas:i,gasPrice:a,maxFeePerGas:c,maxPriorityFeePerGas:u,nonce:f,to:p,value:l}){let d=In({from:r?.address,to:p,value:typeof l<"u"&&`${nt(l)} ${o?.nativeCurrency?.symbol||"ETH"}`,data:s,gas:i,gasPrice:typeof a<"u"&&`${Fe(a)} gwei`,maxFeePerGas:typeof c<"u"&&`${Fe(c)} gwei`,maxPriorityFeePerGas:typeof u<"u"&&`${Fe(u)} gwei`,nonce:f});super(t.shortMessage,{cause:t,docsPath:n,metaMessages:[...t.metaMessages?[...t.metaMessages," "]:[],"Estimate Gas Arguments:",d].filter(Boolean),name:"EstimateGasExecutionError"}),Object.defineProperty(this,"cause",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=t}};Er();gi();function Ih(e,{docsPath:t,...r}){let n=(()=>{let o=Yr(e,r);return o instanceof Pt?e:o})();return new Nc(n,{docsPath:t,...r})}wi();Xr();Oc();Qr();Pe();go();Y();var Mc=class extends g{constructor(){super("`baseFeeMultiplier` must be greater than 1.",{name:"BaseFeeScalarError"})}},en=class extends g{constructor(){super("Chain does not support EIP-1559 fees.",{name:"Eip1559FeesNotSupportedError"})}},zc=class extends g{constructor({maxPriorityFeePerGas:t}){super(`\`maxFeePerGas\` cannot be less than the \`maxPriorityFeePerGas\` (${Fe(t)} gwei).`,{name:"MaxFeePerGasTooLowError"})}};Ve();Y();var ns=class extends g{constructor({blockHash:t,blockNumber:r}){let n="Block";t&&(n=`Block at hash "${t}"`),r&&(n=`Block at number "${r}"`),super(`${n} could not be found.`,{name:"BlockNotFoundError"})}};V();Fc();Ve();Fc();var Lf={"0x0":"legacy","0x1":"eip2930","0x2":"eip1559","0x3":"eip4844","0x4":"eip7702"};function Un(e){let t={...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,chainId:e.chainId?Te(e.chainId):void 0,gas:e.gas?BigInt(e.gas):void 0,gasPrice:e.gasPrice?BigInt(e.gasPrice):void 0,maxFeePerBlobGas:e.maxFeePerBlobGas?BigInt(e.maxFeePerBlobGas):void 0,maxFeePerGas:e.maxFeePerGas?BigInt(e.maxFeePerGas):void 0,maxPriorityFeePerGas:e.maxPriorityFeePerGas?BigInt(e.maxPriorityFeePerGas):void 0,nonce:e.nonce?Te(e.nonce):void 0,to:e.to?e.to:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,type:e.type?Lf[e.type]:void 0,typeHex:e.type?e.type:void 0,value:e.value?BigInt(e.value):void 0,v:e.v?BigInt(e.v):void 0};return e.authorizationList&&(t.authorizationList=A1(e.authorizationList)),t.yParity=(()=>{if(e.yParity)return Number(e.yParity);if(typeof t.v=="bigint"){if(t.v===0n||t.v===27n)return 0;if(t.v===1n||t.v===28n)return 1;if(t.v>=35n)return t.v%2n===0n?1:0}})(),t.type==="legacy"&&(delete t.accessList,delete t.maxFeePerBlobGas,delete t.maxFeePerGas,delete t.maxPriorityFeePerGas,delete t.yParity),t.type==="eip2930"&&(delete t.maxFeePerBlobGas,delete t.maxFeePerGas,delete t.maxPriorityFeePerGas),t.type==="eip1559"&&delete t.maxFeePerBlobGas,t}var kh=ts("transaction",Un);function A1(e){return e.map(t=>({address:t.address,chainId:Number(t.chainId),nonce:Number(t.nonce),r:t.r,s:t.s,yParity:Number(t.yParity)}))}function vi(e){let t=(e.transactions??[]).map(r=>typeof r=="string"?r:Un(r));return{...e,baseFeePerGas:e.baseFeePerGas?BigInt(e.baseFeePerGas):null,blobGasUsed:e.blobGasUsed?BigInt(e.blobGasUsed):void 0,difficulty:e.difficulty?BigInt(e.difficulty):void 0,excessBlobGas:e.excessBlobGas?BigInt(e.excessBlobGas):void 0,gasLimit:e.gasLimit?BigInt(e.gasLimit):void 0,gasUsed:e.gasUsed?BigInt(e.gasUsed):void 0,hash:e.hash?e.hash:null,logsBloom:e.logsBloom?e.logsBloom:null,nonce:e.nonce?e.nonce:null,number:e.number?BigInt(e.number):null,size:e.size?BigInt(e.size):void 0,timestamp:e.timestamp?BigInt(e.timestamp):void 0,transactions:t,totalDifficulty:e.totalDifficulty?BigInt(e.totalDifficulty):null}}var _h=ts("block",vi);async function Qe(e,{blockHash:t,blockNumber:r,blockTag:n,includeTransactions:o}={}){let s=n??"latest",i=o??!1,a=r!==void 0?R(r):void 0,c=null;if(t?c=await e.request({method:"eth_getBlockByHash",params:[t,i]},{dedupe:!0}):c=await e.request({method:"eth_getBlockByNumber",params:[a||s,i]},{dedupe:!!a}),!c)throw new ns({blockHash:t,blockNumber:r});return(e.chain?.formatters?.block?.format||vi)(c)}async function os(e){let t=await e.request({method:"eth_gasPrice"});return BigInt(t)}async function Bh(e,t){return Df(e,t)}async function Df(e,t){let{block:r,chain:n=e.chain,request:o}=t||{};try{let s=n?.fees?.maxPriorityFeePerGas??n?.fees?.defaultPriorityFee;if(typeof s=="function"){let a=r||await $(e,Qe,"getBlock")({}),c=await s({block:a,client:e,request:o});if(c===null)throw new Error;return c}if(typeof s<"u")return s;let i=await e.request({method:"eth_maxPriorityFeePerGas"});return ge(i)}catch{let[s,i]=await Promise.all([r?Promise.resolve(r):$(e,Qe,"getBlock")({}),$(e,os,"getGasPrice")({})]);if(typeof s.baseFeePerGas!="bigint")throw new en;let a=i-s.baseFeePerGas;return a<0n?0n:a}}async function Rh(e,t){return Lc(e,t)}async function Lc(e,t){let{block:r,chain:n=e.chain,request:o,type:s="eip1559"}=t||{},i=await(async()=>typeof n?.fees?.baseFeeMultiplier=="function"?n.fees.baseFeeMultiplier({block:r,client:e,request:o}):n?.fees?.baseFeeMultiplier??1.2)();if(i<1)throw new Mc;let c=10**(i.toString().split(".")[1]?.length??0),u=l=>l*BigInt(Math.ceil(i*c))/BigInt(c),f=r||await $(e,Qe,"getBlock")({});if(typeof n?.fees?.estimateFeesPerGas=="function"){let l=await n.fees.estimateFeesPerGas({block:r,client:e,multiply:u,request:o,type:s});if(l!==null)return l}if(s==="eip1559"){if(typeof f.baseFeePerGas!="bigint")throw new en;let l=typeof o?.maxPriorityFeePerGas=="bigint"?o.maxPriorityFeePerGas:await Df(e,{block:f,chain:n,request:o}),d=u(f.baseFeePerGas);return{maxFeePerGas:o?.maxFeePerGas??d+l,maxPriorityFeePerGas:l}}return{gasPrice:o?.gasPrice??u(await $(e,os,"getGasPrice")({}))}}Ve();V();async function ss(e,{address:t,blockTag:r="latest",blockNumber:n}){let o=await e.request({method:"eth_getTransactionCount",params:[t,n?R(n):r]},{dedupe:!!n});return Te(o)}He();V();function is(e){let{kzg:t}=e,r=e.to??(typeof e.blobs[0]=="string"?"hex":"bytes"),n=typeof e.blobs[0]=="string"?e.blobs.map(s=>Ne(s)):e.blobs,o=[];for(let s of n)o.push(Uint8Array.from(t.blobToKzgCommitment(s)));return r==="bytes"?o:o.map(s=>se(s))}He();V();function as(e){let{kzg:t}=e,r=e.to??(typeof e.blobs[0]=="string"?"hex":"bytes"),n=typeof e.blobs[0]=="string"?e.blobs.map(i=>Ne(i)):e.blobs,o=typeof e.commitments[0]=="string"?e.commitments.map(i=>Ne(i)):e.commitments,s=[];for(let i=0;ise(i))}V();mf();Rt();He();V();function $h(e,t){let r=t||"hex",n=Gr(Ie(e,{strict:!1})?Et(e):e);return r==="bytes"?n:M(n)}function Nh(e){let{commitment:t,version:r=1}=e,n=e.to??(typeof t=="string"?"hex":"bytes"),o=$h(t,"bytes");return o.set([r],0),n==="bytes"?o:se(o)}function Dc(e){let{commitments:t,version:r}=e,n=e.to??(typeof t[0]=="string"?"hex":"bytes"),o=[];for(let s of t)o.push(Nh({commitment:s,to:n,version:r}));return o}Y();var Hc=class extends g{constructor({maxSize:t,size:r}){super("Blob size is too large.",{metaMessages:[`Max: ${t} bytes`,`Given: ${r} bytes`],name:"BlobSizeTooLargeError"})}},cs=class extends g{constructor(){super("Blob data must not be empty.",{name:"EmptyBlobError"})}},jc=class extends g{constructor({hash:t,size:r}){super(`Versioned hash "${t}" size is invalid.`,{metaMessages:["Expected: 32",`Received: ${r}`],name:"InvalidVersionedHashSizeError"})}},qc=class extends g{constructor({hash:t,version:r}){super(`Versioned hash "${t}" version is invalid.`,{metaMessages:[`Expected: ${1}`,`Received: ${r}`],name:"InvalidVersionedHashVersionError"})}};oc();wt();He();V();function Fh(e){let t=e.to??(typeof e.data=="string"?"hex":"bytes"),r=typeof e.data=="string"?Ne(e.data):e.data,n=ne(r);if(!n)throw new cs;if(n>761855)throw new Hc({maxSize:761855,size:n});let o=[],s=!0,i=0;for(;s;){let a=xo(new Uint8Array(131072)),c=0;for(;c<4096;){let u=r.slice(i,i+31);if(a.pushByte(0),a.pushBytes(u),u.length<31){a.pushByte(128),s=!1;break}c++,i+=31}o.push(a)}return t==="bytes"?o.map(a=>a.bytes):o.map(a=>se(a.bytes))}function Gc(e){let{data:t,kzg:r,to:n}=e,o=e.blobs??Fh({data:t,to:n}),s=e.commitments??is({blobs:o,kzg:r,to:n}),i=e.proofs??as({blobs:o,commitments:s,kzg:r,to:n}),a=[];for(let c=0;c"u"&&p)if(c){let h=await m();l.nonce=await c.consume({address:p.address,chainId:h,client:e})}else l.nonce=await $(e,ss,"getTransactionCount")({address:p.address,blockTag:"pending"});if((u.includes("blobVersionedHashes")||u.includes("sidecars"))&&n&&i){let h=is({blobs:n,kzg:i});if(u.includes("blobVersionedHashes")){let b=Dc({commitments:h,to:"hex"});l.blobVersionedHashes=b}if(u.includes("sidecars")){let b=as({blobs:n,commitments:h,kzg:i}),v=Gc({blobs:n,commitments:h,proofs:b,to:"hex"});l.sidecars=v}}if(u.includes("chainId")&&(l.chainId=await m()),(u.includes("fees")||u.includes("type"))&&typeof f>"u")try{l.type=Vc(l)}catch{let h=Oh.get(e.uid);typeof h>"u"&&(h=typeof(await y())?.baseFeePerGas=="bigint",Oh.set(e.uid,h)),l.type=h?"eip1559":"legacy"}if(u.includes("fees"))if(l.type!=="legacy"&&l.type!=="eip2930"){if(typeof l.maxFeePerGas>"u"||typeof l.maxPriorityFeePerGas>"u"){let h=await y(),{maxFeePerGas:b,maxPriorityFeePerGas:v}=await Lc(e,{block:h,chain:o,request:l});if(typeof t.maxPriorityFeePerGas>"u"&&t.maxFeePerGas&&t.maxFeePerGas"u"){let h=await y(),{gasPrice:b}=await Lc(e,{block:h,chain:o,request:l,type:"legacy"});l.gasPrice=b}}return u.includes("gas")&&typeof s>"u"&&(l.gas=await $(e,us,"estimateGas")({...l,account:p&&{address:p.address,type:"json-rpc"}})),ft(l),delete l.parameters,l}V();async function Wc(e,{address:t,blockNumber:r,blockTag:n="latest"}){let o=r?R(r):void 0,s=await e.request({method:"eth_getBalance",params:[t,o||n]});return BigInt(s)}async function us(e,t){let{account:r=e.account}=t,n=r?Z(r):void 0;try{let L=function(B){let{block:O,request:N,rpcStateOverride:G}=B;return e.request({method:"eth_estimateGas",params:G?[N,O??"latest",G]:O?[N,O]:[N]})};var o=L;let{accessList:s,authorizationList:i,blobs:a,blobVersionedHashes:c,blockNumber:u,blockTag:f,data:p,gas:l,gasPrice:d,maxFeePerBlobGas:y,maxFeePerGas:x,maxPriorityFeePerGas:m,nonce:h,value:b,stateOverride:v,...A}=await tn(e,{...t,parameters:n?.type==="local"?void 0:["blobVersionedHashes"]}),S=(u?R(u):void 0)||f,T=rs(v),_=await(async()=>{if(A.to)return A.to;if(i&&i.length>0)return await $c({authorization:i[0]}).catch(()=>{throw new g("`to` is required. Could not infer from `authorizationList`")})})();ft(t);let C=e.chain?.formatters?.transactionRequest?.format,z=(C||gt)({...Zr(A,{format:C}),from:n?.address,accessList:s,authorizationList:i,blobs:a,blobVersionedHashes:c,data:p,gas:l,gasPrice:d,maxFeePerBlobGas:y,maxFeePerGas:x,maxPriorityFeePerGas:m,nonce:h,to:_,value:b}),ae=BigInt(await L({block:S,request:z,rpcStateOverride:T}));if(i){let B=await Wc(e,{address:z.from}),O=await Promise.all(i.map(async N=>{let{address:G}=N,j=await L({block:S,request:{authorizationList:void 0,data:p,from:n?.address,to:G,value:R(B)},rpcStateOverride:T}).catch(()=>100000n);return 2n*BigInt(j)}));ae+=O.reduce((N,G)=>N+G,0n)}return ae}catch(s){throw Ih(s,{...t,account:n,chain:e.chain})}}async function Uh(e,t){let{abi:r,address:n,args:o,functionName:s,dataSuffix:i,...a}=t,c=be({abi:r,args:o,functionName:s});try{return await $(e,us,"estimateGas")({data:`${c}${i?i.replace("0x",""):""}`,to:n,...a})}catch(u){let f=a.account?Z(a.account):void 0;throw yt(u,{abi:r,address:n,args:o,docsPath:"/docs/contract/estimateContractGas",functionName:s,sender:f?.address})}}Mr();Ae();ps();He();Ut();ni();Ae();wt();ni();af();ci();ur();var Mh="/docs/contract/decodeEventLog";function fs(e){let{abi:t,data:r,strict:n,topics:o}=e,s=n??!0,[i,...a]=o;if(!i)throw new Ra({docsPath:Mh});let c=t.length===1?t[0]:t.find(x=>x.type==="event"&&i===Or(Re(x)));if(!(c&&"name"in c)||c.type!=="event")throw new po(i,{docsPath:Mh});let{name:u,inputs:f}=c,p=f?.some(x=>!("name"in x&&x.name)),l=p?[]:{},d=f.filter(x=>"indexed"in x&&x.indexed);for(let x=0;x!("indexed"in x&&x.indexed));if(y.length>0){if(r&&r!=="0x")try{let x=mr(y,r);if(x)if(p)l=[...l,...x];else for(let m=0;m0?l:void 0}}function I1({param:e,value:t}){return e.type==="string"||e.type==="bytes"||e.type==="tuple"||e.type.match(/^(.*)\[(\d+)?\]$/)?t:(mr([e],t)||[])[0]}function ls(e){let{abi:t,args:r,logs:n,strict:o=!0}=e,s=(()=>{if(e.eventName)return Array.isArray(e.eventName)?e.eventName:[e.eventName]})();return n.map(i=>{try{let a=t.find(u=>u.type==="event"&&i.topics[0]===Or(u));if(!a)return null;let c=fs({...i,abi:[a],strict:o});return s&&!s.includes(c.eventName)||!P1({args:c.args,inputs:a.inputs,matchArgs:r})?null:{...c,...i}}catch(a){let c,u;if(a instanceof po)return null;if(a instanceof Nt||a instanceof Vt){if(o)return null;c=a.abiItem.name,u=a.abiItem.inputs?.some(f=>!("name"in f&&f.name))}return{...i,args:u?[]:{},eventName:c}}}).filter(Boolean)}function P1(e){let{args:t,inputs:r,matchArgs:n}=e;if(!n)return!0;if(!t)return!1;function o(s,i,a){try{return s.type==="address"?rr(i,a):s.type==="string"||s.type==="bytes"?de(Et(i))===a:i===a}catch{return!1}}return Array.isArray(t)&&Array.isArray(n)?n.every((s,i)=>{if(s==null)return!0;let a=r[i];return a?(Array.isArray(s)?s:[s]).some(u=>o(a,u,t[i])):!1}):typeof t=="object"&&!Array.isArray(t)&&typeof n=="object"&&!Array.isArray(n)?Object.entries(n).every(([s,i])=>{if(i==null)return!0;let a=r.find(u=>u.name===s);return a?(Array.isArray(i)?i:[i]).some(u=>o(a,u,t[s])):!1}):!1}V();function et(e,{args:t,eventName:r}={}){return{...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,logIndex:e.logIndex?Number(e.logIndex):null,transactionHash:e.transactionHash?e.transactionHash:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,...r?{args:t,eventName:r}:{}}}async function ds(e,{address:t,blockHash:r,fromBlock:n,toBlock:o,event:s,events:i,args:a,strict:c}={}){let u=c??!1,f=i??(s?[s]:void 0),p=[];f&&(p=[f.flatMap(x=>Xt({abi:[x],eventName:x.name,args:i?void 0:a}))],s&&(p=p[0]));let l;r?l=await e.request({method:"eth_getLogs",params:[{address:t,topics:p,blockHash:r}]}):l=await e.request({method:"eth_getLogs",params:[{address:t,topics:p,fromBlock:typeof n=="bigint"?R(n):n,toBlock:typeof o=="bigint"?R(o):o}]});let d=l.map(y=>et(y));return f?ls({abi:f,args:a,logs:d,strict:u}):d}async function Kc(e,t){let{abi:r,address:n,args:o,blockHash:s,eventName:i,fromBlock:a,toBlock:c,strict:u}=t,f=i?ct({abi:r,name:i}):void 0,p=f?void 0:r.filter(l=>l.type==="event");return $(e,ds,"getLogs")({address:n,args:o,blockHash:s,event:f,events:p,fromBlock:a,toBlock:c,strict:u})}rn();ht();xs();async function Ke(e,t){let{abi:r,address:n,args:o,functionName:s,...i}=t,a=be({abi:r,args:o,functionName:s});try{let{data:c}=await $(e,nr,"call")({...i,data:a,to:n});return lt({abi:r,args:o,functionName:s,data:c||"0x"})}catch(c){throw yt(c,{abi:r,address:n,args:o,docsPath:"/docs/contract/readContract",functionName:s})}}Pe();rn();ht();xs();async function ry(e,t){let{abi:r,address:n,args:o,dataSuffix:s,functionName:i,...a}=t,c=a.account?Z(a.account):e.account,u=be({abi:r,args:o,functionName:i});try{let{data:f}=await $(e,nr,"call")({batch:!1,data:`${u}${s?s.replace("0x",""):""}`,to:n,...a,account:c}),p=lt({abi:r,args:o,functionName:i,data:f||"0x"}),l=r.filter(d=>"name"in d&&d.name===t.functionName);return{result:p,request:{abi:l,address:n,args:o,dataSuffix:s,functionName:i,...a,account:c}}}catch(f){throw yt(f,{abi:r,address:n,args:o,docsPath:"/docs/contract/simulateContract",functionName:i,sender:c?.address})}}Ae();fi();var el=new Map,ny=new Map,O1=0;function tt(e,t,r){let n=++O1,o=()=>el.get(e)||[],s=()=>{let f=o();el.set(e,f.filter(p=>p.id!==n))},i=()=>{let f=o();if(!f.some(l=>l.id===n))return;let p=ny.get(e);f.length===1&&p&&p(),s()},a=o();if(el.set(e,[...a,{id:n,fns:t}]),a&&a.length>0)return i;let c={};for(let f in t)c[f]=(...p)=>{let l=o();if(l.length!==0)for(let d of l)d.fns[f]?.(...p)};let u=r(c);return typeof u=="function"&&ny.set(e,u),i}async function Ti(e){return new Promise(t=>setTimeout(t,e))}function _t(e,{emitOnBegin:t,initialWaitTime:r,interval:n}){let o=!0,s=()=>o=!1;return(async()=>{let a;t&&(a=await e({unpoll:s}));let c=await r?.(a)??n;await Ti(c);let u=async()=>{o&&(await e({unpoll:s}),await Ti(n),u())};u()})(),s}Xe();var U1=new Map,M1=new Map;function oy(e){let t=(o,s)=>({clear:()=>s.delete(o),get:()=>s.get(o),set:i=>s.set(o,i)}),r=t(e,U1),n=t(e,M1);return{clear:()=>{r.clear(),n.clear()},promise:r,response:n}}async function sy(e,{cacheKey:t,cacheTime:r=Number.POSITIVE_INFINITY}){let n=oy(t),o=n.response.get();if(o&&r>0&&new Date().getTime()-o.created.getTime()`blockNumber.${e}`;async function or(e,{cacheTime:t=e.cacheTime}={}){let r=await sy(()=>e.request({method:"eth_blockNumber"}),{cacheKey:z1(e.uid),cacheTime:t});return BigInt(r)}async function on(e,{filter:t}){let r="strict"in t&&t.strict,n=await t.request({method:"eth_getFilterChanges",params:[t.id]});if(typeof n[0]=="string")return n;let o=n.map(s=>et(s));return!("abi"in t)||!t.abi?o:ls({abi:t.abi,logs:o,strict:r})}async function sn(e,{filter:t}){return t.request({method:"eth_uninstallFilter",params:[t.id]})}function iy(e,t){let{abi:r,address:n,args:o,batch:s=!0,eventName:i,fromBlock:a,onError:c,onLogs:u,poll:f,pollingInterval:p=e.pollingInterval,strict:l}=t;return(typeof f<"u"?f:typeof a=="bigint"?!0:!(e.transport.type==="webSocket"||e.transport.type==="fallback"&&e.transport.transports[0].config.type==="webSocket"))?(()=>{let m=l??!1,h=ee(["watchContractEvent",n,o,s,e.uid,i,p,m,a]);return tt(h,{onLogs:u,onError:c},b=>{let v;a!==void 0&&(v=a-1n);let A,k=!1,S=_t(async()=>{if(!k){try{A=await $(e,ec,"createContractEventFilter")({abi:r,address:n,args:o,eventName:i,strict:m,fromBlock:a})}catch{}k=!0;return}try{let T;if(A)T=await $(e,on,"getFilterChanges")({filter:A});else{let _=await $(e,or,"getBlockNumber")({});v&&v<_?T=await $(e,Kc,"getContractEvents")({abi:r,address:n,args:o,eventName:i,fromBlock:v+1n,toBlock:_,strict:m}):T=[],v=_}if(T.length===0)return;if(s)b.onLogs(T);else for(let _ of T)b.onLogs([_])}catch(T){A&&T instanceof er&&(k=!1),b.onError?.(T)}},{emitOnBegin:!0,interval:p});return async()=>{A&&await $(e,sn,"uninstallFilter")({filter:A}),S()}})})():(()=>{let m=l??!1,h=ee(["watchContractEvent",n,o,s,e.uid,i,p,m]),b=!0,v=()=>b=!1;return tt(h,{onLogs:u,onError:c},A=>((async()=>{try{let k=(()=>{if(e.transport.type==="fallback"){let _=e.transport.transports.find(C=>C.config.type==="webSocket");return _?_.value:e.transport}return e.transport})(),S=i?Xt({abi:r,eventName:i,args:o}):[],{unsubscribe:T}=await k.subscribe({params:["logs",{address:n,topics:S}],onData(_){if(!b)return;let C=_.result;try{let{eventName:D,args:z}=fs({abi:r,data:C.data,topics:C.topics,strict:l}),L=et(C,{args:z,eventName:D});A.onLogs([L])}catch(D){let z,L;if(D instanceof Nt||D instanceof Vt){if(l)return;z=D.abiItem.name,L=D.abiItem.inputs?.some(B=>!("name"in B&&B.name))}let ae=et(C,{args:L?[]:{},eventName:z});A.onLogs([ae])}},onError(_){A.onError?.(_)}});v=T,b||v()}catch(k){c?.(k)}})(),()=>v()))})()}Pe();Y();var je=class extends g{constructor({docsPath:t}={}){super(["Could not find an Account to execute with this Action.","Please provide an Account with the `account` argument on the Action, or by supplying an `account` to the Client."].join(` +`),{docsPath:t,docsSlug:"account",name:"AccountNotFoundError"})}},an=class extends g{constructor({docsPath:t,metaMessages:r,type:n}){super(`Account type "${n}" is not supported.`,{docsPath:t,metaMessages:r,name:"AccountTypeNotSupportedError"})}};ht();Pe();Y();ms();function uu({chain:e,currentChainId:t}){if(!e)throw new eu;if(t!==e.id)throw new Qc({chain:e,currentChainId:t})}Er();zt();gi();function pu(e,{docsPath:t,...r}){let n=(()=>{let o=Yr(e,r);return o instanceof Pt?e:o})();return new hc(n,{docsPath:t,...r})}wi();Xr();oi();Qr();async function bs(e,{serializedTransaction:t}){return e.request({method:"eth_sendRawTransaction",params:[t]},{retryCount:0})}var tl=new Kt(128);async function gs(e,t){let{account:r=e.account,chain:n=e.chain,accessList:o,authorizationList:s,blobs:i,data:a,gas:c,gasPrice:u,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:l,nonce:d,type:y,value:x,...m}=t;if(typeof r>"u")throw new je({docsPath:"/docs/actions/wallet/sendTransaction"});let h=r?Z(r):null;try{ft(t);let b=await(async()=>{if(t.to)return t.to;if(t.to!==null&&s&&s.length>0)return await $c({authorization:s[0]}).catch(()=>{throw new g("`to` is required. Could not infer from `authorizationList`.")})})();if(h?.type==="json-rpc"||h===null){let v;n!==null&&(v=await $(e,Ct,"getChainId")({}),uu({currentChainId:v,chain:n}));let A=e.chain?.formatters?.transactionRequest?.format,S=(A||gt)({...Zr(m,{format:A}),accessList:o,authorizationList:s,blobs:i,chainId:v,data:a,from:h?.address,gas:c,gasPrice:u,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:l,nonce:d,to:b,type:y,value:x}),T=tl.get(e.uid),_=T?"wallet_sendTransaction":"eth_sendTransaction";try{return await e.request({method:_,params:[S]},{retryCount:0})}catch(C){if(T===!1)throw C;let D=C;if(D.name==="InvalidInputRpcError"||D.name==="InvalidParamsRpcError"||D.name==="MethodNotFoundRpcError"||D.name==="MethodNotSupportedRpcError")return await e.request({method:"wallet_sendTransaction",params:[S]},{retryCount:0}).then(z=>(tl.set(e.uid,!0),z)).catch(z=>{let L=z;throw L.name==="MethodNotFoundRpcError"||L.name==="MethodNotSupportedRpcError"?(tl.set(e.uid,!1),D):L});throw D}}if(h?.type==="local"){let v=await $(e,tn,"prepareTransactionRequest")({account:h,accessList:o,authorizationList:s,blobs:i,chain:n,data:a,gas:c,gasPrice:u,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:l,nonce:d,nonceManager:h.nonceManager,parameters:[...Hf,"sidecars"],type:y,value:x,...m,to:b}),A=n?.serializers?.transaction,k=await h.signTransaction(v,{serializer:A});return await $(e,bs,"sendRawTransaction")({serializedTransaction:k})}throw h?.type==="smart"?new an({metaMessages:["Consider using the `sendUserOperation` Action instead."],docsPath:"/docs/actions/bundler/sendUserOperation",type:"smart"}):new an({docsPath:"/docs/actions/wallet/sendTransaction",type:h?.type})}catch(b){throw b instanceof an?b:pu(b,{...t,account:h,chain:t.chain||void 0})}}async function ay(e,t){let{abi:r,account:n=e.account,address:o,args:s,dataSuffix:i,functionName:a,...c}=t;if(typeof n>"u")throw new je({docsPath:"/docs/contract/writeContract"});let u=n?Z(n):null,f=be({abi:r,args:s,functionName:a});try{return await $(e,gs,"sendTransaction")({data:`${f}${i?i.replace("0x",""):""}`,to:o,account:u,...c})}catch(p){throw yt(p,{abi:r,address:o,args:s,docsPath:"/docs/contract/writeContract",functionName:a,sender:u?.address})}}Y();nu();Xe();Ve();Ve();var rl={"0x0":"reverted","0x1":"success"};function cy(e){let t={...e,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,contractAddress:e.contractAddress?e.contractAddress:null,cumulativeGasUsed:e.cumulativeGasUsed?BigInt(e.cumulativeGasUsed):null,effectiveGasPrice:e.effectiveGasPrice?BigInt(e.effectiveGasPrice):null,gasUsed:e.gasUsed?BigInt(e.gasUsed):null,logs:e.logs?e.logs.map(r=>et(r)):null,to:e.to?e.to:null,transactionIndex:e.transactionIndex?Te(e.transactionIndex):null,status:e.status?rl[e.status]:null,type:e.type?Lf[e.type]||e.type:null};return e.blobGasPrice&&(t.blobGasPrice=BigInt(e.blobGasPrice)),e.blobGasUsed&&(t.blobGasUsed=BigInt(e.blobGasUsed)),t}async function fu(e,t){let{atomic:r=!1,chainId:n,receipts:o,version:s="2.0.0",...i}=await e.request({method:"wallet_getCallsStatus",params:[t.id]}),[a,c]=(()=>{let u=i.status;return u>=100&&u<200?["pending",u]:u>=200&&u<300?["success",u]:u>=300&&u<700?["failure",u]:u==="CONFIRMED"?["success",200]:u==="PENDING"?["pending",100]:[void 0,u]})();return{...i,atomic:r,chainId:n?Te(n):void 0,receipts:o?.map(u=>({...u,blockNumber:ge(u.blockNumber),gasUsed:ge(u.gasUsed),status:rl[u.status]}))??[],statusCode:c,status:a,version:s}}async function uy(e,t){let{id:r,pollingInterval:n=e.pollingInterval,status:o=({statusCode:l})=>l>=200,timeout:s=6e4}=t,i=ee(["waitForCallsStatus",e.uid,r]),{promise:a,resolve:c,reject:u}=hs(),f,p=tt(i,{resolve:c,reject:u},l=>{let d=_t(async()=>{let y=x=>{clearTimeout(f),d(),x(),p()};try{let x=await fu(e,{id:r});if(!o(x))return;y(()=>l.resolve(x))}catch(x){y(()=>l.reject(x))}},{interval:n,emitOnBegin:!0});return d});return f=s?setTimeout(()=>{p(),clearTimeout(f),u(new nl({id:r}))},s):void 0,await a}var nl=class extends g{constructor({id:t}){super(`Timed out while waiting for call bundle with id "${t}" to be confirmed.`,{name:"WaitForCallsStatusTimeoutError"})}};Pe();var lu=256,du;function mu(e=11){if(!du||lu+e>256*2){du="",lu=0;for(let t=0;t<256;t++)du+=(256+Math.random()*256|0).toString(16).substring(1)}return du.substring(lu,lu+++e)}function hu(e){let{batch:t,cacheTime:r=e.pollingInterval??4e3,ccipRead:n,key:o="base",name:s="Base Client",pollingInterval:i=4e3,type:a="base"}=e,c=e.chain,u=e.account?Z(e.account):void 0,{config:f,request:p,value:l}=e.transport({chain:c,pollingInterval:i}),d={...f,...l},y={account:u,batch:t,cacheTime:r,ccipRead:n,chain:c,key:o,name:s,pollingInterval:i,request:p,transport:d,type:a,uid:mu()};function x(m){return h=>{let b=h(m);for(let A in y)delete b[A];let v={...m,...b};return Object.assign(v,{extend:x(v)})}}return Object.assign(y,{extend:x(y)})}Y();kn();fi();V();oi();var yu=new Kt(8192);function py(e,{enabled:t=!0,id:r}){if(!t||!r)return e();if(yu.get(r))return yu.get(r);let n=e().finally(()=>yu.delete(r));return yu.set(r,n),n}function Si(e,{delay:t=100,retryCount:r=2,shouldRetry:n=()=>!0}={}){return new Promise((o,s)=>{let i=async({count:a=0}={})=>{let c=async({error:u})=>{let f=typeof t=="function"?t({count:a,error:u}):t;f&&await Ti(f),i({count:a+1})};try{let u=await e();o(u)}catch(u){if(a{let{dedupe:o=!1,methods:s,retryDelay:i=150,retryCount:a=3,uid:c}={...t,...n},{method:u}=r;if(s?.exclude?.includes(u))throw new Hr(new Error("method not supported"),{method:u});if(s?.include&&!s.include.includes(u))throw new Hr(new Error("method not supported"),{method:u});let f=o?Wt(`${c}.${ee(r)}`):void 0;return py(()=>Si(async()=>{try{return await e(r)}catch(p){let l=p;switch(l.code){case Ao.code:throw new Ao(l);case To.code:throw new To(l);case So.code:throw new So(l,{method:r.method});case Io.code:throw new Io(l);case hr.code:throw new hr(l);case er.code:throw new er(l);case Po.code:throw new Po(l);case Co.code:throw new Co(l);case ko.code:throw new ko(l);case Hr.code:throw new Hr(l,{method:r.method});case _n.code:throw new _n(l);case _o.code:throw new _o(l);case Bn.code:throw new Bn(l);case Bo.code:throw new Bo(l);case Ro.code:throw new Ro(l);case $o.code:throw new $o(l);case No.code:throw new No(l);case Fo.code:throw new Fo(l);case Oo.code:throw new Oo(l);case Uo.code:throw new Uo(l);case Mo.code:throw new Mo(l);case zo.code:throw new zo(l);case Lo.code:throw new Lo(l);case Do.code:throw new Do(l);case Ho.code:throw new Ho(l);case 5e3:throw new Bn(l);default:throw p instanceof g?p:new vc(l)}}},{delay:({count:p,error:l})=>{if(l&&l instanceof St){let d=l?.headers?.get("Retry-After");if(d?.match(/\d/))return Number.parseInt(d)*1e3}return~~(1<L1(p)}),{enabled:o,id:f})}}function L1(e){return"code"in e&&typeof e.code=="number"?e.code===-1||e.code===_n.code||e.code===hr.code:e instanceof St&&e.status?e.status===403||e.status===408||e.status===413||e.status===429||e.status===500||e.status===502||e.status===503||e.status===504:!0}function xu({key:e,methods:t,name:r,request:n,retryCount:o=3,retryDelay:s=150,timeout:i,type:a},c){let u=mu();return{config:{key:e,methods:t,name:r,request:n,retryCount:o,retryDelay:s,timeout:i,type:a},request:fy(n,{methods:t,retryCount:o,retryDelay:s,uid:u}),value:c}}function ol(e,t={}){let{key:r="custom",methods:n,name:o="Custom Provider",retryDelay:s}=t;return({retryCount:i})=>xu({key:r,methods:n,name:o,request:e.request.bind(e),retryCount:t.retryCount??i,retryDelay:s,type:"custom"})}kn();Y();var bu=class extends g{constructor(){super("No URL was provided to the Transport. Please provide a valid RPC URL to the Transport.",{docsPath:"/docs/clients/intro",name:"UrlRequiredError"})}};Zf();kn();function ly(e,{errorInstance:t=new Error("timed out"),timeout:r,signal:n}){return new Promise((o,s)=>{(async()=>{let i;try{let a=new AbortController;r>0&&(i=setTimeout(()=>{n?a.abort():s(t)},r)),o(await e({signal:a?.signal||null}))}catch(a){a?.name==="AbortError"&&s(t),s(a)}finally{clearTimeout(i)}})()})}Xe();function D1(){return{current:0,take(){return this.current++},reset(){this.current=0}}}var sl=D1();function dy(e,t={}){return{async request(r){let{body:n,onRequest:o=t.onRequest,onResponse:s=t.onResponse,timeout:i=t.timeout??1e4}=r,a={...t.fetchOptions??{},...r.fetchOptions??{}},{headers:c,method:u,signal:f}=a;try{let p=await ly(async({signal:d})=>{let y={...a,body:Array.isArray(n)?ee(n.map(b=>({jsonrpc:"2.0",id:b.id??sl.take(),...b}))):ee({jsonrpc:"2.0",id:n.id??sl.take(),...n}),headers:{"Content-Type":"application/json",...c},method:u||"POST",signal:f||(i>0?d:null)},x=new Request(e,y),m=await o?.(x,y)??{...y,url:e};return await fetch(m.url??e,m)},{errorInstance:new pi({body:n,url:e}),timeout:i,signal:!0});s&&await s(p);let l;if(p.headers.get("Content-Type")?.startsWith("application/json"))l=await p.json();else{l=await p.text();try{l=JSON.parse(l||"{}")}catch(d){if(p.ok)throw d;l={error:l}}}if(!p.ok)throw new St({body:n,details:ee(l.error)||p.statusText,headers:p.headers,status:p.status,url:e});return l}catch(p){throw p instanceof St||p instanceof pi?p:new St({body:n,cause:p,url:e})}}}}function il(e,t={}){let{batch:r,fetchOptions:n,key:o="http",methods:s,name:i="HTTP JSON-RPC",onFetchRequest:a,onFetchResponse:c,retryDelay:u,raw:f}=t;return({chain:p,retryCount:l,timeout:d})=>{let{batchSize:y=1e3,wait:x=0}=typeof r=="object"?r:{},m=t.retryCount??l,h=d??t.timeout??1e4,b=e||p?.rpcUrls.default.http[0];if(!b)throw new bu;let v=dy(b,{fetchOptions:n,onRequest:a,onResponse:c,timeout:h});return xu({key:o,methods:s,name:i,async request({method:A,params:k}){let S={method:A,params:k},{schedule:T}=ou({id:b,wait:x,shouldSplitBatch(z){return z.length>y},fn:z=>v.request({body:z}),sort:(z,L)=>z.id-L.id}),_=async z=>r?T(z):[await v.request({body:z})],[{error:C,result:D}]=await _(S);if(f)return{error:C,result:D};if(C)throw new Dr({body:S,error:C,url:b});return D},retryCount:m,retryDelay:u,timeout:h,type:"http"},{fetchOptions:n,url:b})}}nn();rn();ht();Ln();En();V();si();Y();Lr();function ws(e,t){if(!(e instanceof g))return!1;let r=e.walk(n=>n instanceof Cn);return r instanceof Cn?!!(r.data?.errorName==="ResolverNotFound"||r.data?.errorName==="ResolverWildcardNotSupported"||r.data?.errorName==="ResolverNotContract"||r.data?.errorName==="ResolverError"||r.data?.errorName==="HttpError"||r.reason?.includes("Wildcard on non-extended resolvers is not supported")||t==="reverse"&&r.reason===tc[50]):!1}cu();at();He();V();Ut();Rt();function gu(e){if(e.length!==66||e.indexOf("[")!==0||e.indexOf("]")!==65)return null;let t=`0x${e.slice(1,65)}`;return Ie(t)?t:null}function vs(e){let t=new Uint8Array(32).fill(0);if(!e)return se(t);let r=e.split(".");for(let n=r.length-1;n>=0;n-=1){let o=gu(r[n]),s=o?Et(o):de(Ft(r[n]),"bytes");t=de(rt([t,s]),"bytes")}return se(t)}He();function my(e){return`[${e.slice(2)}]`}He();V();Ut();function hy(e){let t=new Uint8Array(32).fill(0);return e?gu(e)||de(Ft(e)):se(t)}function cn(e){let t=e.replace(/^\.|\.$/gm,"");if(t.length===0)return new Uint8Array(1);let r=new Uint8Array(Ft(t).byteLength+2),n=0,o=t.split(".");for(let s=0;s255&&(i=Ft(my(hy(o[s])))),r[n]=i.length,r.set(i,n+1),n+=i.length+1}return r.byteLength!==n+1?r.slice(0,n+1):r}async function yy(e,t){let{blockNumber:r,blockTag:n,coinType:o,name:s,gatewayUrls:i,strict:a}=t,{chain:c}=e,u=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw new Error("client chain not configured. universalResolverAddress is required.");return kt({blockNumber:r,chain:c,contract:"ensUniversalResolver"})})(),f=c?.ensTlds;if(f&&!f.some(p=>s.endsWith(p)))return null;try{let p=be({abi:Gf,functionName:"addr",...o!=null?{args:[vs(s),BigInt(o)]}:{args:[vs(s)]}}),l={address:u,abi:Zc,functionName:"resolve",args:[M(cn(s)),p,i??[ys]],blockNumber:r,blockTag:n},y=await $(e,Ke,"readContract")(l);if(y[0]==="0x")return null;let x=lt({abi:Gf,args:o!=null?[vs(s),BigInt(o)]:void 0,functionName:"addr",data:y[0]});return x==="0x"||$e(x)==="0x00"?null:x}catch(p){if(a)throw p;if(ws(p,"resolve"))return null;throw p}}Y();var wu=class extends g{constructor({data:t}){super("Unable to extract image from metadata. The metadata may be malformed or invalid.",{metaMessages:["- Metadata must be a JSON object with at least an `image`, `image_url` or `image_data` property.","",`Provided data: ${JSON.stringify(t)}`],name:"EnsAvatarInvalidMetadataError"})}},un=class extends g{constructor({reason:t}){super(`ENS NFT avatar URI is invalid. ${t}`,{name:"EnsAvatarInvalidNftUriError"})}},Es=class extends g{constructor({uri:t}){super(`Unable to resolve ENS avatar URI "${t}". The URI may be malformed, invalid, or does not respond with a valid image.`,{name:"EnsAvatarUriResolutionError"})}},vu=class extends g{constructor({namespace:t}){super(`ENS NFT avatar namespace "${t}" is not supported. Must be "erc721" or "erc1155".`,{name:"EnsAvatarUnsupportedNamespaceError"})}};var H1=/(?https?:\/\/[^\/]*|ipfs:\/|ipns:\/|ar:\/)?(?\/)?(?ipfs\/|ipns\/)?(?[\w\-.]+)(?\/.*)?/,j1=/^(Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,})(\/(?[\w\-.]+))?(?\/.*)?$/,q1=/^data:([a-zA-Z\-/+]*);base64,([^"].*)/,G1=/^data:([a-zA-Z\-/+]*)?(;[a-zA-Z0-9].*?)?(,)/;async function V1(e){try{let t=await fetch(e,{method:"HEAD"});return t.status===200?t.headers.get("content-type")?.startsWith("image/"):!1}catch(t){return typeof t=="object"&&typeof t.response<"u"||!globalThis.hasOwnProperty("Image")?!1:new Promise(r=>{let n=new Image;n.onload=()=>{r(!0)},n.onerror=()=>{r(!1)},n.src=e})}}function xy(e,t){return e?e.endsWith("/")?e.slice(0,-1):e:t}function al({uri:e,gatewayUrls:t}){let r=q1.test(e);if(r)return{uri:e,isOnChain:!0,isEncoded:r};let n=xy(t?.ipfs,"https://ipfs.io"),o=xy(t?.arweave,"https://arweave.net"),s=e.match(H1),{protocol:i,subpath:a,target:c,subtarget:u=""}=s?.groups||{},f=i==="ipns:/"||a==="ipns/",p=i==="ipfs:/"||a==="ipfs/"||j1.test(e);if(e.startsWith("http")&&!f&&!p){let d=e;return t?.arweave&&(d=e.replace(/https:\/\/arweave.net/g,t?.arweave)),{uri:d,isOnChain:!1,isEncoded:!1}}if((f||p)&&c)return{uri:`${n}/${f?"ipns":"ipfs"}/${c}${u}`,isOnChain:!1,isEncoded:!1};if(i==="ar:/"&&c)return{uri:`${o}/${c}${u||""}`,isOnChain:!1,isEncoded:!1};let l=e.replace(G1,"");if(l.startsWith("o.json());return await Eu({gatewayUrls:e,uri:cl(r)})}catch{throw new Es({uri:t})}}async function Eu({gatewayUrls:e,uri:t}){let{uri:r,isOnChain:n}=al({uri:t,gatewayUrls:e});if(n||await V1(r))return r;throw new Es({uri:t})}function gy(e){let t=e;t.startsWith("did:nft:")&&(t=t.replace("did:nft:","").replace(/_/g,"/"));let[r,n,o]=t.split("/"),[s,i]=r.split(":"),[a,c]=n.split(":");if(!s||s.toLowerCase()!=="eip155")throw new un({reason:"Only EIP-155 supported"});if(!i)throw new un({reason:"Chain ID not found"});if(!c)throw new un({reason:"Contract address not found"});if(!o)throw new un({reason:"Token ID not found"});if(!a)throw new un({reason:"ERC namespace not found"});return{chainID:Number.parseInt(i),namespace:a.toLowerCase(),contractAddress:c,tokenID:o}}async function wy(e,{nft:t}){if(t.namespace==="erc721")return Ke(e,{address:t.contractAddress,abi:[{name:"tokenURI",type:"function",stateMutability:"view",inputs:[{name:"tokenId",type:"uint256"}],outputs:[{name:"",type:"string"}]}],functionName:"tokenURI",args:[BigInt(t.tokenID)]});if(t.namespace==="erc1155")return Ke(e,{address:t.contractAddress,abi:[{name:"uri",type:"function",stateMutability:"view",inputs:[{name:"_id",type:"uint256"}],outputs:[{name:"",type:"string"}]}],functionName:"uri",args:[BigInt(t.tokenID)]});throw new vu({namespace:t.namespace})}async function vy(e,{gatewayUrls:t,record:r}){return/eip155:/i.test(r)?W1(e,{gatewayUrls:t,record:r}):Eu({uri:r,gatewayUrls:t})}async function W1(e,{gatewayUrls:t,record:r}){let n=gy(r),o=await wy(e,{nft:n}),{uri:s,isOnChain:i,isEncoded:a}=al({uri:o,gatewayUrls:t});if(i&&(s.includes("data:application/json;base64,")||s.startsWith("{"))){let u=a?atob(s.replace("data:application/json;base64,","")):s,f=JSON.parse(u);return Eu({uri:cl(f),gatewayUrls:t})}let c=n.tokenID;return n.namespace==="erc1155"&&(c=c.replace("0x","").padStart(64,"0")),by({gatewayUrls:t,uri:s.replace(/(?:0x)?{id}/,c)})}nn();rn();ht();Ln();V();cu();async function Au(e,t){let{blockNumber:r,blockTag:n,key:o,name:s,gatewayUrls:i,strict:a}=t,{chain:c}=e,u=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw new Error("client chain not configured. universalResolverAddress is required.");return kt({blockNumber:r,chain:c,contract:"ensUniversalResolver"})})(),f=c?.ensTlds;if(f&&!f.some(p=>s.endsWith(p)))return null;try{let p={address:u,abi:Zc,functionName:"resolve",args:[M(cn(s)),be({abi:qf,functionName:"text",args:[vs(s),o]}),i??[ys]],blockNumber:r,blockTag:n},d=await $(e,Ke,"readContract")(p);if(d[0]==="0x")return null;let y=lt({abi:qf,functionName:"text",data:d[0]});return y===""?null:y}catch(p){if(a)throw p;if(ws(p,"resolve"))return null;throw p}}async function Ey(e,{blockNumber:t,blockTag:r,assetGatewayUrls:n,name:o,gatewayUrls:s,strict:i,universalResolverAddress:a}){let c=await $(e,Au,"getEnsText")({blockNumber:t,blockTag:r,key:"avatar",name:o,universalResolverAddress:a,gatewayUrls:s,strict:i});if(!c)return null;try{return await vy(e,{record:c,gatewayUrls:n})}catch{return null}}nn();Ln();V();async function Ay(e,{address:t,blockNumber:r,blockTag:n,gatewayUrls:o,strict:s,universalResolverAddress:i}){let a=i;if(!a){if(!e.chain)throw new Error("client chain not configured. universalResolverAddress is required.");a=kt({blockNumber:r,chain:e.chain,contract:"ensUniversalResolver"})}let c=`${t.toLowerCase().substring(2)}.addr.reverse`;try{let u={address:a,abi:Lh,functionName:"reverse",args:[M(cn(c))],blockNumber:r,blockTag:n},f=$(e,Ke,"readContract"),[p,l]=o?await f({...u,args:[...u.args,o]}):await f(u);return t.toLowerCase()!==l.toLowerCase()?null:p}catch(u){if(s)throw u;if(ws(u,"reverse"))return null;throw u}}Ln();V();async function Ty(e,t){let{blockNumber:r,blockTag:n,name:o}=t,{chain:s}=e,i=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!s)throw new Error("client chain not configured. universalResolverAddress is required.");return kt({blockNumber:r,chain:s,contract:"ensUniversalResolver"})})(),a=s?.ensTlds;if(a&&!a.some(u=>o.endsWith(u)))throw new Error(`${o} is not a valid ENS TLD (${a?.join(", ")}) for chain "${s.name}" (id: ${s.id}).`);let[c]=await $(e,Ke,"readContract")({address:i,abi:[{inputs:[{type:"bytes"}],name:"findResolver",outputs:[{type:"address"},{type:"bytes32"}],stateMutability:"view",type:"function"}],functionName:"findResolver",args:[M(cn(o))],blockNumber:r,blockTag:n});return c}xs();Pe();V();Kf();wi();Xr();Qr();async function Tu(e,t){let{account:r=e.account,blockNumber:n,blockTag:o="latest",blobs:s,data:i,gas:a,gasPrice:c,maxFeePerBlobGas:u,maxFeePerGas:f,maxPriorityFeePerGas:p,to:l,value:d,...y}=t,x=r?Z(r):void 0;try{ft(t);let h=(n?R(n):void 0)||o,b=e.chain?.formatters?.transactionRequest?.format,A=(b||gt)({...Zr(y,{format:b}),from:x?.address,blobs:s,data:i,gas:a,gasPrice:c,maxFeePerBlobGas:u,maxFeePerGas:f,maxPriorityFeePerGas:p,to:l,value:d}),k=await e.request({method:"eth_createAccessList",params:[A,h]});return{accessList:k.accessList,gasUsed:BigInt(k.gasUsed)}}catch(m){throw ru(m,{...t,account:x,chain:e.chain})}}async function Sy(e){let t=zr(e,{method:"eth_newBlockFilter"}),r=await e.request({method:"eth_newBlockFilter"});return{id:r,request:t(r),type:"block"}}V();async function Su(e,{address:t,args:r,event:n,events:o,fromBlock:s,strict:i,toBlock:a}={}){let c=o??(n?[n]:void 0),u=zr(e,{method:"eth_newFilter"}),f=[];c&&(f=[c.flatMap(d=>Xt({abi:[d],eventName:d.name,args:r}))],n&&(f=f[0]));let p=await e.request({method:"eth_newFilter",params:[{address:t,fromBlock:typeof s=="bigint"?R(s):s,toBlock:typeof a=="bigint"?R(a):a,...f.length?{topics:f}:{}}]});return{abi:c,args:r,eventName:n?n.name:void 0,fromBlock:s,id:p,request:u(p),strict:!!i,toBlock:a,type:"event"}}async function Iu(e){let t=zr(e,{method:"eth_newPendingTransactionFilter"}),r=await e.request({method:"eth_newPendingTransactionFilter"});return{id:r,request:t(r),type:"transaction"}}async function Iy(e){let t=await e.request({method:"eth_blobBaseFee"});return BigInt(t)}Ve();V();async function Py(e,{blockHash:t,blockNumber:r,blockTag:n="latest"}={}){let o=r!==void 0?R(r):void 0,s;return t?s=await e.request({method:"eth_getBlockTransactionCountByHash",params:[t]},{dedupe:!0}):s=await e.request({method:"eth_getBlockTransactionCountByNumber",params:[o||n]},{dedupe:!!o}),Te(s)}V();async function ul(e,{address:t,blockNumber:r,blockTag:n="latest"}){let o=r!==void 0?R(r):void 0,s=await e.request({method:"eth_getCode",params:[t,o||n]},{dedupe:!!o});if(s!=="0x")return s}Y();var Pu=class extends g{constructor({address:t}){super(`No EIP-712 domain found on contract "${t}".`,{metaMessages:["Ensure that:",`- The contract is deployed at the address "${t}".`,"- `eip712Domain()` function exists on the contract.","- `eip712Domain()` function matches signature to ERC-5267 specification."],name:"Eip712DomainNotFoundError"})}};async function Cy(e,t){let{address:r,factory:n,factoryData:o}=t;try{let[s,i,a,c,u,f,p]=await $(e,Ke,"readContract")({abi:K1,address:r,functionName:"eip712Domain",factory:n,factoryData:o});return{domain:{name:i,version:a,chainId:Number(c),verifyingContract:u,salt:f},extensions:p,fields:s}}catch(s){let i=s;throw i.name==="ContractFunctionExecutionError"&&i.cause.name==="ContractFunctionZeroDataError"?new Pu({address:r}):i}}var K1=[{inputs:[],name:"eip712Domain",outputs:[{name:"fields",type:"bytes1"},{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"},{name:"salt",type:"bytes32"},{name:"extensions",type:"uint256[]"}],stateMutability:"view",type:"function"}];V();function ky(e){return{baseFeePerGas:e.baseFeePerGas.map(t=>BigInt(t)),gasUsedRatio:e.gasUsedRatio,oldestBlock:BigInt(e.oldestBlock),reward:e.reward?.map(t=>t.map(r=>BigInt(r)))}}async function _y(e,{blockCount:t,blockNumber:r,blockTag:n="latest",rewardPercentiles:o}){let s=r?R(r):void 0,i=await e.request({method:"eth_feeHistory",params:[R(t),s||n,o]},{dedupe:!!s});return ky(i)}async function By(e,{filter:t}){let r=t.strict??!1,o=(await t.request({method:"eth_getFilterLogs",params:[t.id]})).map(s=>et(s));return t.abi?ls({abi:t.abi,logs:o,strict:r}):o}V();function Ry(e){return{formatters:void 0,fees:void 0,serializers:void 0,...e}}Ae();Mt();Xe();Y();var Cu=class extends g{constructor({domain:t}){super(`Invalid domain "${ee(t)}".`,{metaMessages:["Must be a valid EIP-712 domain."]})}},ku=class extends g{constructor({primaryType:t,types:r}){super(`Invalid primary type \`${t}\` must be one of \`${JSON.stringify(Object.keys(r))}\`.`,{docsPath:"/api/glossary/Errors#typeddatainvalidprimarytypeerror",metaMessages:["Check that the primary type is a key in `types`."]})}},_u=class extends g{constructor({type:t}){super(`Struct type "${t}" is invalid.`,{metaMessages:["Struct type must not be a Solidity type."],name:"InvalidStructTypeError"})}};At();wt();V();rf();Yt();at();V();Ut();function $y(e){let{domain:t={},message:r,primaryType:n}=e,o={EIP712Domain:Ru({domain:t}),...e.types};Bu({domain:t,message:r,primaryType:n,types:o});let s=["0x1901"];return t&&s.push(Y1({domain:t,types:o})),n!=="EIP712Domain"&&s.push(Ny({data:r,primaryType:n,types:o})),de(rt(s))}function Y1({domain:e,types:t}){return Ny({data:e,primaryType:"EIP712Domain",types:t})}function Ny({data:e,primaryType:t,types:r}){let n=Fy({data:e,primaryType:t,types:r});return de(n)}function Fy({data:e,primaryType:t,types:r}){let n=[{type:"bytes32"}],o=[Z1({primaryType:t,types:r})];for(let s of r[t]){let[i,a]=Uy({types:r,name:s.name,type:s.type,value:e[s.name]});n.push(i),o.push(a)}return We(n,o)}function Z1({primaryType:e,types:t}){let r=M(X1({primaryType:e,types:t}));return de(r)}function X1({primaryType:e,types:t}){let r="",n=Oy({primaryType:e,types:t});n.delete(e);let o=[e,...Array.from(n).sort()];for(let s of o)r+=`${s}(${t[s].map(({name:i,type:a})=>`${a} ${i}`).join(",")})`;return r}function Oy({primaryType:e,types:t},r=new Set){let o=e.match(/^\w*/u)?.[0];if(r.has(o)||t[o]===void 0)return r;r.add(o);for(let s of t[o])Oy({primaryType:s.type,types:t},r);return r}function Uy({types:e,name:t,type:r,value:n}){if(e[r]!==void 0)return[{type:"bytes32"},de(Fy({data:n,primaryType:r,types:e}))];if(r==="bytes")return n=`0x${(n.length%2?"0":"")+n.slice(2)}`,[{type:"bytes32"},de(n)];if(r==="string")return[{type:"bytes32"},de(M(n))];if(r.lastIndexOf("]")===r.length-1){let o=r.slice(0,r.lastIndexOf("[")),s=n.map(i=>Uy({name:t,type:o,types:e,value:i}));return[{type:"bytes32"},de(We(s.map(([i])=>i),s.map(([,i])=>i)))]}return[{type:r},n]}Xe();function My(e){let{domain:t,message:r,primaryType:n,types:o}=e,s=(c,u)=>{let f={...u};for(let p of c){let{name:l,type:d}=p;d==="address"&&(f[l]=f[l].toLowerCase())}return f},i=o.EIP712Domain?t?s(o.EIP712Domain,t):{}:{},a=(()=>{if(n!=="EIP712Domain")return s(o[n],r)})();return ee({domain:i,message:a,primaryType:n,types:o})}function Bu(e){let{domain:t,message:r,primaryType:n,types:o}=e,s=(i,a)=>{for(let c of i){let{name:u,type:f}=c,p=a[u],l=f.match(Ja);if(l&&(typeof p=="number"||typeof p=="bigint")){let[x,m,h]=l;R(p,{signed:m==="int",size:Number.parseInt(h)/8})}if(f==="address"&&typeof p=="string"&&!ie(p))throw new fe({address:p});let d=f.match(hm);if(d){let[x,m]=d;if(m&&ne(p)!==Number.parseInt(m))throw new Fa({expectedSize:Number.parseInt(m),givenSize:ne(p)})}let y=o[f];y&&(J1(f),s(y,p))}};if(o.EIP712Domain&&t){if(typeof t!="object")throw new Cu({domain:t});s(o.EIP712Domain,t)}if(n!=="EIP712Domain")if(o[n])s(o[n],r);else throw new ku({primaryType:n,types:o})}function Ru({domain:e}){return[typeof e?.name=="string"&&{name:"name",type:"string"},e?.version&&{name:"version",type:"string"},(typeof e?.chainId=="number"||typeof e?.chainId=="bigint")&&{name:"chainId",type:"uint256"},e?.verifyingContract&&{name:"verifyingContract",type:"address"},e?.salt&&{name:"salt",type:"bytes32"}].filter(Boolean)}function J1(e){if(e==="address"||e==="bool"||e==="string"||e.startsWith("bytes")||e.startsWith("uint")||e.startsWith("int"))throw new _u({type:e})}ht();V();zt();at();En();V();Uc();Mt();Y();ms();Er();At();wt();Ur();Ve();function zy(e){let{authorizationList:t}=e;if(t)for(let r of t){let{chainId:n}=r,o=r.address;if(!ie(o))throw new fe({address:o});if(n<0)throw new Ar({chainId:n})}$u(e)}function Ly(e){let{blobVersionedHashes:t}=e;if(t){if(t.length===0)throw new cs;for(let r of t){let n=ne(r),o=Te(Tt(r,0,1));if(n!==32)throw new jc({hash:r,size:n});if(o!==1)throw new qc({hash:r,version:o})}}$u(e)}function $u(e){let{chainId:t,maxPriorityFeePerGas:r,maxFeePerGas:n,to:o}=e;if(t<=0)throw new Ar({chainId:t});if(o&&!ie(o))throw new fe({address:o});if(n&&n>Jr)throw new pt({maxFeePerGas:n});if(r&&n&&r>n)throw new It({maxFeePerGas:n,maxPriorityFeePerGas:r})}function Dy(e){let{chainId:t,maxPriorityFeePerGas:r,gasPrice:n,maxFeePerGas:o,to:s}=e;if(t<=0)throw new Ar({chainId:t});if(s&&!ie(s))throw new fe({address:s});if(r||o)throw new g("`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid EIP-2930 Transaction attribute.");if(n&&n>Jr)throw new pt({maxFeePerGas:n})}function Hy(e){let{chainId:t,maxPriorityFeePerGas:r,gasPrice:n,maxFeePerGas:o,to:s}=e;if(s&&!ie(s))throw new fe({address:s});if(typeof t<"u"&&t<=0)throw new Ar({chainId:t});if(r||o)throw new g("`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid Legacy Transaction attribute.");if(n&&n>Jr)throw new pt({maxFeePerGas:n})}Mt();zt();At();function Dn(e){if(!e||e.length===0)return[];let t=[];for(let r=0;r"u"||typeof d>"u")){let v=typeof e.blobs[0]=="string"?e.blobs:e.blobs.map(S=>se(S)),A=e.kzg,k=is({blobs:v,kzg:A});if(typeof l>"u"&&(l=Dc({commitments:k})),typeof d>"u"){let S=as({blobs:v,commitments:k,kzg:A});d=Gc({blobs:v,commitments:k,proofs:S})}}let y=Dn(f),x=[M(r),o?M(o):"0x",u?M(u):"0x",c?M(c):"0x",n?M(n):"0x",s??"0x",i?M(i):"0x",p??"0x",y,a?M(a):"0x",l??[],...pn(e,t)],m=[],h=[],b=[];if(d)for(let v=0;v{if(t.v>=35n)return(t.v-35n)/2n>0?t.v:27n+(t.v===35n?0n:1n);if(r>0)return BigInt(r*2)+BigInt(35n+t.v-27n);let d=27n+(t.v===27n?0n:1n);if(t.v!==d)throw new lc({v:t.v});return d})(),p=$e(t.r),l=$e(t.s);u=[...u,M(f),p==="0x00"?"0x":p,l==="0x00"?"0x":l]}else r>0&&(u=[...u,M(r),"0x","0x"]);return bt(u)}function pn(e,t){let r=t??e,{v:n,yParity:o}=r;if(typeof r.r>"u")return[];if(typeof r.s>"u")return[];if(typeof n>"u"&&typeof o>"u")return[];let s=$e(r.r),i=$e(r.s);return[typeof o=="number"?o?M(1):"0x":n===0n?"0x":n===1n?M(1):n===27n?"0x":M(1),s==="0x00"?"0x":s,i==="0x00"?"0x":i]}function qy(e){if(!e||e.length===0)return[];let t=[];for(let r of e){let{chainId:n,nonce:o,...s}=r,i=r.address;t.push([n?M(n):"0x",i,o?M(o):"0x",...pn({},s)])}return t}Ve();Ut();var Gy=`Ethereum Signed Message: +`;at();wt();V();function Vy(e){let t=typeof e=="string"?Wt(e):typeof e.raw=="string"?e.raw:se(e.raw),r=Wt(`${Gy}${ne(t)}`);return rt([r,t])}function Nu(e,t){return de(Vy(e),t)}var Fu="0x6492649264926492649264926492649264926492649264926492649264926492";Ur();function Wy(e){return tf(e,-32)===Fu}Yt();at();He();function Ky(e){let{address:t,data:r,signature:n,to:o="hex"}=e,s=_e([We([{type:"address"},{type:"bytes"},{type:"bytes"}],[t,r,n]),Fu]);return o==="hex"?s:Ne(s)}Y();var Ou=class extends g{constructor({value:t}){super(`Number \`${t}\` is not a valid decimal number.`,{name:"InvalidDecimalNumberError"})}};function Yy(e,t){if(!/^(-?)([0-9]*)\.?([0-9]*)$/.test(e))throw new Ou({value:e});let[r,n="0"]=e.split("."),o=r.startsWith("-");if(o&&(r=r.slice(1)),n=n.replace(/(0+)$/,""),t===0)Math.round(+`.${n}`)===1&&(r=`${BigInt(r)+1n}`),n="";else if(n.length>t){let[s,i,a]=[n.slice(0,t-1),n.slice(t-1,t),n.slice(t)],c=Math.round(+`${i}.${a}`);c>9?n=`${BigInt(s)+BigInt(1)}0`.padStart(s.length+1,"0"):n=`${s}${c}`,n.length>t&&(n=n.slice(1),r=`${BigInt(r)+1n}`),n=n.slice(0,t)}else n=n.padEnd(t,"0");return BigInt(`${o?"-":""}${r}${n}`)}ac();function pl(e,t="wei"){return Yy(e,ic[t])}function ow(e){return e.map(t=>({...t,value:BigInt(t.value)}))}function Zy(e){return{...e,balance:e.balance?BigInt(e.balance):void 0,nonce:e.nonce?Te(e.nonce):void 0,storageProof:e.storageProof?ow(e.storageProof):void 0}}async function Xy(e,{address:t,blockNumber:r,blockTag:n,storageKeys:o}){let s=n??"latest",i=r!==void 0?R(r):void 0,a=await e.request({method:"eth_getProof",params:[t,o,i||s]});return Zy(a)}V();async function Jy(e,{address:t,blockNumber:r,blockTag:n="latest",slot:o}){let s=r!==void 0?R(r):void 0;return await e.request({method:"eth_getStorageAt",params:[t,o,s||n]})}zt();V();async function As(e,{blockHash:t,blockNumber:r,blockTag:n,hash:o,index:s}){let i=n||"latest",a=r!==void 0?R(r):void 0,c=null;if(o?c=await e.request({method:"eth_getTransactionByHash",params:[o]},{dedupe:!0}):t?c=await e.request({method:"eth_getTransactionByBlockHashAndIndex",params:[t,R(s)]},{dedupe:!0}):(a||i)&&(c=await e.request({method:"eth_getTransactionByBlockNumberAndIndex",params:[a||i,R(s)]},{dedupe:!!a})),!c)throw new wo({blockHash:t,blockNumber:r,blockTag:i,hash:o,index:s});return(e.chain?.formatters?.transaction?.format||Un)(c)}async function Qy(e,{hash:t,transactionReceipt:r}){let[n,o]=await Promise.all([$(e,or,"getBlockNumber")({}),t?$(e,As,"getTransaction")({hash:t}):void 0]),s=r?.blockNumber||o?.blockNumber;return s?n-s+1n:0n}zt();async function Ii(e,{hash:t}){let r=await e.request({method:"eth_getTransactionReceipt",params:[t]},{dedupe:!0});if(!r)throw new vo({hash:t});return(e.chain?.formatters?.transactionReceipt?.format||cy)(r)}nn();Ae();Y();Lr();rn();ht();Ln();async function ex(e,t){let{allowFailure:r=!0,batchSize:n,blockNumber:o,blockTag:s,multicallAddress:i,stateOverride:a}=t,c=t.contracts,u=n??(typeof e.batch?.multicall=="object"&&e.batch.multicall.batchSize||1024),f=i;if(!f){if(!e.chain)throw new Error("client chain not configured. multicallAddress is required.");f=kt({blockNumber:o,chain:e.chain,contract:"multicall3"})}let p=[[]],l=0,d=0;for(let m=0;m0&&d>u&&p[l].length>0&&(l++,d=(k.length-2)/2,p[l]=[]),p[l]=[...p[l],{allowFailure:!0,callData:k,target:b}]}catch(k){let S=yt(k,{abi:h,address:b,args:v,docsPath:"/docs/contract/multicall",functionName:A});if(!r)throw S;p[l]=[...p[l],{allowFailure:!0,callData:"0x",target:b}]}}let y=await Promise.allSettled(p.map(m=>$(e,Ke,"readContract")({abi:Ei,address:f,args:[m],blockNumber:o,blockTag:s,functionName:"aggregate3",stateOverride:a}))),x=[];for(let m=0;m{if(r.cause instanceof e){if(r.cause.details)return r.cause.details;if(r.cause.shortMessage)return r.cause.shortMessage}return r.cause?.message?r.cause.message:r.details})(),o=r.cause instanceof e&&r.cause.docsPath||r.docsPath,i=`https://oxlib.sh${o??""}`,a=[t||"An error occurred.",...r.metaMessages?["",...r.metaMessages]:[],...n||o?["",n?`Details: ${n}`:void 0,o?`See: ${i}`:void 0]:[]].filter(c=>typeof c=="string").join(` +`);super(a,r.cause?{cause:r.cause}:void 0),Object.defineProperty(this,"details",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"docs",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"docsPath",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"shortMessage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"cause",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"BaseError"}),Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:`ox@${rx()}`}),this.cause=r.cause,this.details=n,this.docs=i,this.docsPath=o,this.shortMessage=t}walk(t){return nx(this,t)}};function nx(e,t){return t?.(e)?e:e&&typeof e=="object"&&"cause"in e&&e.cause?nx(e.cause,t):t?null:e}var sw="#__bigint";function ox(e,t,r){return JSON.stringify(e,(n,o)=>typeof t=="function"?t(n,o):typeof o=="bigint"?o.toString()+sw:o,r)}function sx(e,t){if(fl(e)>t)throw new Uu({givenSize:fl(e),maxSize:t})}var Tr={zero:48,nine:57,A:65,F:70,a:97,f:102};function ll(e){if(e>=Tr.zero&&e<=Tr.nine)return e-Tr.zero;if(e>=Tr.A&&e<=Tr.F)return e-(Tr.A-10);if(e>=Tr.a&&e<=Tr.f)return e-(Tr.a-10)}function ix(e,t={}){let{dir:r,size:n=32}=t;if(n===0)return e;if(e.length>n)throw new Mu({size:e.length,targetSize:n,type:"Bytes"});let o=new Uint8Array(n);for(let s=0;st)throw new zu({givenSize:qe(e),maxSize:t})}function ax(e,t){if(typeof t=="number"&&t>0&&t>qe(e)-1)throw new Ci({offset:t,position:"start",size:qe(e)})}function cx(e,t,r){if(typeof t=="number"&&typeof r=="number"&&qe(e)!==r-t)throw new Ci({offset:r,position:"end",size:qe(e)})}function ml(e,t={}){let{dir:r,size:n=32}=t;if(n===0)return e;let o=e.replace("0x","");if(o.length>n*2)throw new Lu({size:Math.ceil(o.length/2),targetSize:n,type:"Hex"});return`0x${o[r==="right"?"padEnd":"padStart"](n*2,"0")}`}var cw=new TextEncoder;function px(e){return e instanceof Uint8Array?e:typeof e=="string"?pw(e):uw(e)}function uw(e){return e instanceof Uint8Array?e:new Uint8Array(e)}function pw(e,t={}){let{size:r}=t,n=e;r&&(Pi(e,r),n=ir(e,r));let o=n.slice(2);o.length%2&&(o=`0${o}`);let s=o.length/2,i=new Uint8Array(s);for(let a=0,c=0;at.toString(16).padStart(2,"0"));function mw(e,t={}){let{strict:r=!1}=t;if(!e)throw new Du(e);if(typeof e!="string")throw new Du(e);if(r&&!/^0x[0-9a-fA-F]*$/.test(e))throw new Hu(e);if(!e.startsWith("0x"))throw new Hu(e)}function dt(...e){return`0x${e.reduce((t,r)=>t+r.replace("0x",""),"")}`}function ju(e,t={}){let r=`0x${Number(e)}`;return typeof t.size=="number"?(Pi(r,t.size),Sr(r,t.size)):r}function Ts(e,t={}){let r="";for(let o=0;os||o{let h=m,b=h.account?Z(h.account):void 0,v={...h,data:h.abi?be(h):h.data,from:h.from??b?.address};return ft(v),gt(v)}),x=l.stateOverrides?rs(l.stateOverrides):void 0;c.push({blockOverrides:d,calls:y,stateOverrides:x})}let f=(r?R(r):void 0)||n;return(await e.request({method:"eth_simulateV1",params:[{blockStateCalls:c,returnFullTransactions:s,traceTransfers:i,validation:a},f]})).map((l,d)=>({...vi(l),calls:l.calls.map((y,x)=>{let{abi:m,args:h,functionName:b,to:v}=o[d].calls[x],A=y.error?.data??y.returnData,k=BigInt(y.gasUsed),S=y.logs?.map(D=>et(D)),T=y.status==="0x1"?"success":"failure",_=m&&T==="success"&&A!=="0x"?lt({abi:m,data:A,functionName:b}):null,C=(()=>{if(T==="success")return;let D;if(y.error?.data==="0x"?D=new vt:y.error&&(D=new Qt(y.error)),!!D)return yt(D,{abi:m??[],address:v,args:h,functionName:b??""})})();return{data:A,gasUsed:k,logs:S,status:T,...T==="success"?{result:_}:{error:C}}})}))}catch(c){let u=c,f=Yr(u,{});throw f instanceof Pt?u:f}}Sa();function yl(e){if(!Number.isSafeInteger(e)||e<0)throw new Error("positive integer expected, got "+e)}function xw(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Bi(e,...t){if(!xw(e))throw new Error("Uint8Array expected");if(t.length>0&&!t.includes(e.length))throw new Error("Uint8Array expected of length "+t+", got length="+e.length)}function xl(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function mx(e,t){Bi(e);let r=t.outputLen;if(e.length>>8&65280|e>>>24&255}function gl(e){for(let t=0;te().update(Gu(n)).digest(),r=e();return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.create=()=>e(),t}function xx(e){let t=(n,o)=>e(o).update(Gu(n)).digest(),r=e({});return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.create=n=>e(n),t}var Vu=BigInt(4294967295),bx=BigInt(32);function ww(e,t=!1){return t?{h:Number(e&Vu),l:Number(e>>bx&Vu)}:{h:Number(e>>bx&Vu)|0,l:Number(e&Vu)|0}}function gx(e,t=!1){let r=new Uint32Array(e.length),n=new Uint32Array(e.length);for(let o=0;oe<>>32-r,vx=(e,t,r)=>t<>>32-r,Ex=(e,t,r)=>t<>>64-r,Ax=(e,t,r)=>e<>>64-r;var Ix=[],Px=[],Cx=[],vw=BigInt(0),Ri=BigInt(1),Ew=BigInt(2),Aw=BigInt(7),Tw=BigInt(256),Sw=BigInt(113);for(let e=0,t=Ri,r=1,n=0;e<24;e++){[r,n]=[n,(2*r+3*n)%5],Ix.push(2*(5*n+r)),Px.push((e+1)*(e+2)/2%64);let o=vw;for(let s=0;s<7;s++)t=(t<>Aw)*Sw)%Tw,t&Ew&&(o^=Ri<<(Ri<r>32?Ex(e,t,r):wx(e,t,r),Sx=(e,t,r)=>r>32?Ax(e,t,r):vx(e,t,r);function Cw(e,t=24){let r=new Uint32Array(10);for(let n=24-t;n<24;n++){for(let i=0;i<10;i++)r[i]=e[i]^e[i+10]^e[i+20]^e[i+30]^e[i+40];for(let i=0;i<10;i+=2){let a=(i+8)%10,c=(i+2)%10,u=r[c],f=r[c+1],p=Tx(u,f,1)^r[a],l=Sx(u,f,1)^r[a+1];for(let d=0;d<50;d+=10)e[i+d]^=p,e[i+d+1]^=l}let o=e[2],s=e[3];for(let i=0;i<24;i++){let a=Px[i],c=Tx(o,s,a),u=Sx(o,s,a),f=Ix[i];o=e[f],s=e[f+1],e[f]=c,e[f+1]=u}for(let i=0;i<50;i+=10){for(let a=0;a<10;a++)r[a]=e[i+a];for(let a=0;a<10;a++)e[i+a]^=~r[(a+2)%10]&r[(a+4)%10]}e[0]^=Iw[n],e[1]^=Pw[n]}r.fill(0)}var Wu=class e extends qu{constructor(t,r,n,o=!1,s=24){if(super(),this.blockLen=t,this.suffix=r,this.outputLen=n,this.enableXOF=o,this.rounds=s,this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,yl(n),0>=this.blockLen||this.blockLen>=200)throw new Error("Sha3 supports only keccak-f1600 function");this.state=new Uint8Array(200),this.state32=hx(this.state)}keccak(){bl||gl(this.state32),Cw(this.state32,this.rounds),bl||gl(this.state32),this.posOut=0,this.pos=0}update(t){xl(this);let{blockLen:r,state:n}=this;t=Gu(t);let o=t.length;for(let s=0;s=n&&this.keccak();let i=Math.min(n-this.posOut,s-o);t.set(r.subarray(this.posOut,this.posOut+i),o),this.posOut+=i,o+=i}return t}xofInto(t){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(t)}xof(t){return yl(t),this.xofInto(new Uint8Array(t))}digestInto(t){if(mx(t,this),this.finished)throw new Error("digest() was already called");return this.writeInto(t),this.destroy(),t}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,this.state.fill(0)}_cloneInto(t){let{blockLen:r,suffix:n,outputLen:o,rounds:s,enableXOF:i}=this;return t||(t=new e(r,n,o,i,s)),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=s,t.suffix=n,t.outputLen=o,t.enableXOF=i,t.destroyed=this.destroyed,t}},fn=(e,t,r)=>yx(()=>new Wu(t,e,r)),KU=fn(6,144,224/8),YU=fn(6,136,256/8),ZU=fn(6,104,384/8),XU=fn(6,72,512/8),JU=fn(1,144,224/8),kx=fn(1,136,256/8),QU=fn(1,104,384/8),eM=fn(1,72,512/8),_x=(e,t,r)=>xx((n={})=>new Wu(t,e,n.dkLen===void 0?r:n.dkLen,!0)),tM=_x(31,168,128/8),rM=_x(31,136,256/8);function Ku(e,t={}){let{as:r=typeof e=="string"?"Hex":"Bytes"}=t,n=kx(px(e));return r==="Bytes"?n:Ts(n)}var Yu=class extends Map{constructor(t){super(),Object.defineProperty(this,"maxSize",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.maxSize=t}get(t){let r=super.get(t);return super.has(t)&&r!==void 0&&(this.delete(t),super.set(t,r)),r}set(t,r){if(super.set(t,r),this.maxSize&&this.size>this.maxSize){let n=this.keys().next().value;n&&this.delete(n)}return this}};var kw={checksum:new Yu(8192)},Zu=kw.checksum;var Bw=/^0x[a-fA-F0-9]{40}$/;function Ps(e,t={}){let{strict:r=!0}=t;if(!Bw.test(e))throw new Xu({address:e,cause:new wl});if(r){if(e.toLowerCase()===e)return;if(Rx(e)!==e)throw new Xu({address:e,cause:new vl})}}function Rx(e){if(Zu.has(e))return Zu.get(e);Ps(e,{strict:!1});let t=e.substring(2).toLowerCase(),r=Ku(fx(t),{as:"Bytes"}),n=t.split("");for(let s=0;s<40;s+=2)r[s>>1]>>4>=8&&n[s]&&(n[s]=n[s].toUpperCase()),(r[s>>1]&15)>=8&&n[s+1]&&(n[s+1]=n[s+1].toUpperCase());let o=`0x${n.join("")}`;return Zu.set(e,o),o}function Ju(e,t={}){let{strict:r=!0}=t??{};try{return Ps(e,{strict:r}),!0}catch{return!1}}var Xu=class extends ce{constructor({address:t,cause:r}){super(`Address "${t}" is invalid.`,{cause:r}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"Address.InvalidAddressError"})}},wl=class extends ce{constructor(){super("Address is not a 20 byte (40 hexadecimal character) value."),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"Address.InvalidInputError"})}},vl=class extends ce{constructor(){super("Address does not match its checksum counterpart."),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"Address.InvalidChecksumError"})}};function ep(e){let t=!0,r="",n=0,o="",s=!1;for(let i=0;iQu(Object.values(e)[s],o)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(n)?r==="number"||r==="bigint":/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(n)?r==="string"||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(n)?Array.isArray(e)&&e.every(o=>Qu(o,{...t,type:n.replace(/(\[[0-9]{0,}\])$/,"")})):!1}}function Al(e,t,r){for(let n in e){let o=e[n],s=t[n];if(o.type==="tuple"&&s.type==="tuple"&&"components"in o&&"components"in s)return Al(o.components,s.components,r[n]);let i=[o.type,s.type];if(i.includes("address")&&i.includes("bytes20")?!0:i.includes("address")&&i.includes("string")?Ju(r[n],{strict:!1}):i.includes("address")&&i.includes("bytes")?Ju(r[n],{strict:!1}):!1)return i}}function tp(e,t={}){let{prepare:r=!0}=t,n=Array.isArray(e)?Ta(e):typeof e=="string"?Ta(e):e;return{...n,...r?{hash:Cs(n)}:{}}}function $x(e,t,r){let{args:n=[],prepare:o=!0}=r??{},s=hl(t,{strict:!1}),i=e.filter(u=>s?u.type==="function"||u.type==="error"?Sl(u)===Is(t,0,4):u.type==="event"?Cs(u)===t:!1:"name"in u&&u.name===t);if(i.length===0)throw new jn({name:t});if(i.length===1)return{...i[0],...o?{hash:Cs(i[0])}:{}};let a;for(let u of i){if(!("inputs"in u))continue;if(!n||n.length===0){if(!u.inputs||u.inputs.length===0)return{...u,...o?{hash:Cs(u)}:{}};continue}if(!u.inputs||u.inputs.length===0||u.inputs.length!==n.length)continue;if(n.every((p,l)=>{let d="inputs"in u&&u.inputs[l];return d?Qu(p,d):!1})){if(a&&"inputs"in a&&a.inputs){let p=Al(u.inputs,a.inputs,n);if(p)throw new Tl({abiItem:u,type:p[0]},{abiItem:a,type:p[1]})}a=u}}let c=(()=>{if(a)return a;let[u,...f]=i;return{...u,overloads:f}})();if(!c)throw new jn({name:t});return{...c,...o?{hash:Cs(c)}:{}}}function Sl(e){return Is(Cs(e),0,4)}function $w(e){let t=typeof e=="string"?e:vn(e);return ep(t)}function Cs(e){return typeof e!="string"&&"hash"in e&&e.hash?e.hash:Ku(Ss($w(e)))}var Tl=class extends ce{constructor(t,r){super("Found ambiguous types in overloaded ABI Items.",{metaMessages:[`\`${t.type}\` in \`${ep(vn(t.abiItem))}\`, and`,`\`${r.type}\` in \`${ep(vn(r.abiItem))}\``,"","These types encode differently and cannot be distinguished at runtime.","Remove one of the ambiguous items in the ABI."]}),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"AbiItem.AmbiguityError"})}},jn=class extends ce{constructor({name:t,data:r,type:n="item"}){let o=t?` with name "${t}"`:r?` with data "${r}"`:"";super(`ABI ${n}${o} not found.`),Object.defineProperty(this,"name",{enumerable:!0,configurable:!0,writable:!0,value:"AbiItem.NotFoundError"})}};var Fx=/^(.*)\[([0-9]*)\]$/,Ox=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,rp=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/,aM=2n**(8n-1n)-1n,cM=2n**(16n-1n)-1n,uM=2n**(24n-1n)-1n,pM=2n**(32n-1n)-1n,fM=2n**(40n-1n)-1n,lM=2n**(48n-1n)-1n,dM=2n**(56n-1n)-1n,mM=2n**(64n-1n)-1n,hM=2n**(72n-1n)-1n,yM=2n**(80n-1n)-1n,xM=2n**(88n-1n)-1n,bM=2n**(96n-1n)-1n,gM=2n**(104n-1n)-1n,wM=2n**(112n-1n)-1n,vM=2n**(120n-1n)-1n,EM=2n**(128n-1n)-1n,AM=2n**(136n-1n)-1n,TM=2n**(144n-1n)-1n,SM=2n**(152n-1n)-1n,IM=2n**(160n-1n)-1n,PM=2n**(168n-1n)-1n,CM=2n**(176n-1n)-1n,kM=2n**(184n-1n)-1n,_M=2n**(192n-1n)-1n,BM=2n**(200n-1n)-1n,RM=2n**(208n-1n)-1n,$M=2n**(216n-1n)-1n,NM=2n**(224n-1n)-1n,FM=2n**(232n-1n)-1n,OM=2n**(240n-1n)-1n,UM=2n**(248n-1n)-1n,MM=2n**(256n-1n)-1n,zM=-(2n**(8n-1n)),LM=-(2n**(16n-1n)),DM=-(2n**(24n-1n)),HM=-(2n**(32n-1n)),jM=-(2n**(40n-1n)),qM=-(2n**(48n-1n)),GM=-(2n**(56n-1n)),VM=-(2n**(64n-1n)),WM=-(2n**(72n-1n)),KM=-(2n**(80n-1n)),YM=-(2n**(88n-1n)),ZM=-(2n**(96n-1n)),XM=-(2n**(104n-1n)),JM=-(2n**(112n-1n)),QM=-(2n**(120n-1n)),ez=-(2n**(128n-1n)),tz=-(2n**(136n-1n)),rz=-(2n**(144n-1n)),nz=-(2n**(152n-1n)),oz=-(2n**(160n-1n)),sz=-(2n**(168n-1n)),iz=-(2n**(176n-1n)),az=-(2n**(184n-1n)),cz=-(2n**(192n-1n)),uz=-(2n**(200n-1n)),pz=-(2n**(208n-1n)),fz=-(2n**(216n-1n)),lz=-(2n**(224n-1n)),dz=-(2n**(232n-1n)),mz=-(2n**(240n-1n)),hz=-(2n**(248n-1n)),yz=-(2n**(256n-1n)),xz=2n**8n-1n,bz=2n**16n-1n,gz=2n**24n-1n,wz=2n**32n-1n,vz=2n**40n-1n,Ez=2n**48n-1n,Az=2n**56n-1n,Tz=2n**64n-1n,Sz=2n**72n-1n,Iz=2n**80n-1n,Pz=2n**88n-1n,Cz=2n**96n-1n,kz=2n**104n-1n,_z=2n**112n-1n,Bz=2n**120n-1n,Rz=2n**128n-1n,$z=2n**136n-1n,Nz=2n**144n-1n,Fz=2n**152n-1n,Oz=2n**160n-1n,Uz=2n**168n-1n,Mz=2n**176n-1n,zz=2n**184n-1n,Lz=2n**192n-1n,Dz=2n**200n-1n,Hz=2n**208n-1n,jz=2n**216n-1n,qz=2n**224n-1n,Gz=2n**232n-1n,Vz=2n**240n-1n,Wz=2n**248n-1n,Kz=2n**256n-1n;function Ux({checksumAddress:e,parameters:t,values:r}){let n=[];for(let o=0;o0?dt(u,c):u}}if(i)return{dynamic:!0,encoded:c}}return{dynamic:!1,encoded:dt(...a.map(({encoded:c})=>c))}}function Uw(e,{type:t}){let[,r]=t.split("bytes"),n=qe(e);if(!r){let o=e;return n%32!==0&&(o=ir(o,Math.ceil((e.length-2)/2/32)*32)),{dynamic:!0,encoded:dt(Sr(Be(n,{size:32})),o)}}if(n!==Number.parseInt(r))throw new $i({expectedSize:Number.parseInt(r),value:e});return{dynamic:!1,encoded:ir(e)}}function Mw(e){if(typeof e!="boolean")throw new ce(`Invalid boolean value: "${e}" (type: ${typeof e}). Expected: \`true\` or \`false\`.`);return{dynamic:!1,encoded:Sr(ju(e))}}function zw(e,{signed:t,size:r}){if(typeof r=="number"){let n=2n**(BigInt(r)-(t?1n:0n))-1n,o=t?-n-1n:0n;if(e>n||ei))}}function Hw(e){let t=e.match(/^(.*)\[(\d+)?\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}function ap(e,t,r){let{checksumAddress:n=!1}=r??{};if(e.length!==t.length)throw new ip({expectedLength:e.length,givenLength:t.length});let o=Ux({checksumAddress:n,parameters:e,values:t}),s=np(o);return s.length===0?"0x":s}function Cl(e,t){if(e.length!==t.length)throw new ip({expectedLength:e.length,givenLength:t.length});let r=[];for(let n=0;n0?ap(n.inputs,t[0]):void 0;return s?dt(o,s):o}function qn(e,t={}){return tp(e,t)}function Vw(e,t,r){let n=$x(e,t,r);if(n.type!=="function")throw new jn({name:t,type:"function"});return n}function Ww(e){return Sl(e)}Pe();var Dx="0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",Dt="0x0000000000000000000000000000000000000000";Jc();Y();ht();var Yw="0x6080604052348015600e575f80fd5b5061016d8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063f8b2cb4f1461002d575b5f80fd5b610047600480360381019061004291906100db565b61005d565b604051610054919061011e565b60405180910390f35b5f8173ffffffffffffffffffffffffffffffffffffffff16319050919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100aa82610081565b9050919050565b6100ba816100a0565b81146100c4575f80fd5b50565b5f813590506100d5816100b1565b92915050565b5f602082840312156100f0576100ef61007d565b5b5f6100fd848285016100c7565b91505092915050565b5f819050919050565b61011881610106565b82525050565b5f6020820190506101315f83018461010f565b9291505056fea26469706673582212203b9fe929fe995c7cf9887f0bdba8a36dd78e8b73f149b17d2d9ad7cd09d2dc6264736f6c634300081a0033";async function Hx(e,t){let{blockNumber:r,blockTag:n,calls:o,stateOverrides:s,traceAssetChanges:i,traceTransfers:a,validation:c}=t,u=t.account?Z(t.account):void 0;if(i&&!u)throw new g("`account` is required when `traceAssetChanges` is true");let f=u?Mx(zx("constructor(bytes, bytes)"),{bytecode:Xc,args:[Yw,Lx(qn("function getBalance(address)"),[u.address])]}):void 0,p=i?await Promise.all(t.calls.map(async F=>{if(!F.data&&!F.abi)return;let{accessList:te}=await Tu(e,{account:u.address,...F,data:F.abi?be(F):F.data});return te.map(({address:he,storageKeys:w})=>w.length>0?he:null)})).then(F=>F.flat().filter(Boolean)):[],l=s?.map(F=>F.address===u?.address?{...F,nonce:0}:F),d=await _i(e,{blockNumber:r,blockTag:n,blocks:[...i?[{calls:[{data:f}],stateOverrides:s},{calls:p.map((F,te)=>({abi:[qn("function balanceOf(address) returns (uint256)")],functionName:"balanceOf",args:[u.address],to:F,from:Dt,nonce:te})),stateOverrides:[{address:Dt,nonce:0}]}]:[],{calls:[...o,{}].map((F,te)=>({...F,from:u?.address,nonce:te})),stateOverrides:l},...i?[{calls:[{data:f}]},{calls:p.map((F,te)=>({abi:[qn("function balanceOf(address) returns (uint256)")],functionName:"balanceOf",args:[u.address],to:F,from:Dt,nonce:te})),stateOverrides:[{address:Dt,nonce:0}]},{calls:p.map((F,te)=>({to:F,abi:[qn("function decimals() returns (uint256)")],functionName:"decimals",from:Dt,nonce:te})),stateOverrides:[{address:Dt,nonce:0}]},{calls:p.map((F,te)=>({to:F,abi:[qn("function tokenURI(uint256) returns (string)")],functionName:"tokenURI",args:[0n],from:Dt,nonce:te})),stateOverrides:[{address:Dt,nonce:0}]},{calls:p.map((F,te)=>({to:F,abi:[qn("function symbol() returns (string)")],functionName:"symbol",from:Dt,nonce:te})),stateOverrides:[{address:Dt,nonce:0}]}]:[]],traceTransfers:a,validation:c}),y=i?d[2]:d[0],[x,m,,h,b,v,A,k]=i?d:[],{calls:S,...T}=y,_=S.slice(0,-1)??[],C=x?.calls??[],D=m?.calls??[],z=[...C,...D].map(F=>F.status==="success"?ge(F.data):null),L=h?.calls??[],ae=b?.calls??[],B=[...L,...ae].map(F=>F.status==="success"?ge(F.data):null),O=(v?.calls??[]).map(F=>F.status==="success"?F.result:null),N=(k?.calls??[]).map(F=>F.status==="success"?F.result:null),G=(A?.calls??[]).map(F=>F.status==="success"?F.result:null),j=[];for(let[F,te]of B.entries()){let he=z[F];if(typeof te!="bigint"||typeof he!="bigint")continue;let w=O[F-1],P=N[F-1],W=G[F-1],J=F===0?{address:Dx,decimals:18,symbol:"ETH"}:{address:p[F-1],decimals:W||w?Number(w??1):void 0,symbol:P??void 0};j.some(X=>X.token.address===J.address)||j.push({token:J,value:{pre:he,post:te,diff:te-he}})}return{assetChanges:j,block:T,results:_}}nn();Jc();Lr();tu();Sn();ps();Rt();V();zf();Ve();He();function jx({r:e,s:t,to:r="hex",v:n,yParity:o}){let s=(()=>{if(o===0||o===1)return o;if(n&&(n===27n||n===28n||n>=35n))return n%2n===0n?1:0;throw new Error("Invalid `v` or `yParity` value")})(),i=`0x${new On.Signature(ge(e),ge(t)).toCompactHex()}${s===0?"1b":"1c"}`;return r==="hex"?i:Ne(i)}xs();async function ks(e,t){let{address:r,factory:n,factoryData:o,hash:s,signature:i,universalSignatureVerifierAddress:a=e.chain?.contracts?.universalSignatureVerifier?.address,...c}=t,u=Ie(i)?i:typeof i=="object"&&"r"in i&&"s"in i?jx(i):se(i),f=await(async()=>!n&&!o||Wy(u)?u:Ky({address:n,data:o,signature:u}))();try{let p=a?{to:a,data:be({abi:Vf,functionName:"isValidSig",args:[r,s,f]}),...c}:{data:zn({abi:Vf,args:[r,s,f],bytecode:qh}),...c},{data:l}=await $(e,nr,"call")(p);return Wp(l??"0x0")}catch(p){try{if(rr(Xa(r),await Rc({hash:s,signature:i})))return!0}catch{}if(p instanceof Eo)return!1;throw p}}async function qx(e,{address:t,message:r,factory:n,factoryData:o,signature:s,...i}){let a=Nu(r);return ks(e,{address:t,factory:n,factoryData:o,hash:a,signature:s,...i})}async function Gx(e,t){let{address:r,factory:n,factoryData:o,signature:s,message:i,primaryType:a,types:c,domain:u,...f}=t,p=$y({message:i,primaryType:a,types:c,domain:u});return ks(e,{address:r,factory:n,factoryData:o,hash:p,signature:s,...f})}zt();nu();Xe();Ve();Xe();function cp(e,{emitOnBegin:t=!1,emitMissed:r=!1,onBlockNumber:n,onError:o,poll:s,pollingInterval:i=e.pollingInterval}){let a=typeof s<"u"?s:!(e.transport.type==="webSocket"||e.transport.type==="fallback"&&e.transport.transports[0].config.type==="webSocket"),c;return a?(()=>{let p=ee(["watchBlockNumber",e.uid,t,r,i]);return tt(p,{onBlockNumber:n,onError:o},l=>_t(async()=>{try{let d=await $(e,or,"getBlockNumber")({cacheTime:0});if(c){if(d===c)return;if(d-c>1&&r)for(let y=c+1n;yc)&&(l.onBlockNumber(d,c),c=d)}catch(d){l.onError?.(d)}},{emitOnBegin:t,interval:i}))})():(()=>{let p=ee(["watchBlockNumber",e.uid,t,r]);return tt(p,{onBlockNumber:n,onError:o},l=>{let d=!0,y=()=>d=!1;return(async()=>{try{let x=(()=>{if(e.transport.type==="fallback"){let h=e.transport.transports.find(b=>b.config.type==="webSocket");return h?h.value:e.transport}return e.transport})(),{unsubscribe:m}=await x.subscribe({params:["newHeads"],onData(h){if(!d)return;let b=ge(h.result?.number);l.onBlockNumber(b,c),c=b},onError(h){l.onError?.(h)}});y=m,d||y()}catch(x){o?.(x)}})(),()=>y()})})()}async function Vx(e,{confirmations:t=1,hash:r,onReplaced:n,pollingInterval:o=e.pollingInterval,retryCount:s=6,retryDelay:i=({count:c})=>~~(1<x(new yc({hash:r})),a):void 0,h=tt(c,{onReplaced:n,resolve:y,reject:x},b=>{let v=$(e,cp,"watchBlockNumber")({emitMissed:!0,emitOnBegin:!0,poll:!0,pollingInterval:o,async onBlockNumber(A){let k=T=>{clearTimeout(m),v(),T(),h()},S=A;if(!l)try{if(p){if(t>1&&(!p.blockNumber||S-p.blockNumber+1nb.resolve(p));return}if(u||(l=!0,await Si(async()=>{u=await $(e,As,"getTransaction")({hash:r}),u.blockNumber&&(S=u.blockNumber)},{delay:i,retryCount:s}),l=!1),p=await $(e,Ii,"getTransactionReceipt")({hash:r}),t>1&&(!p.blockNumber||S-p.blockNumber+1nb.resolve(p))}catch(T){if(T instanceof wo||T instanceof vo){if(!u){l=!1;return}try{f=u,l=!0;let _=await Si(()=>$(e,Qe,"getBlock")({blockNumber:S,includeTransactions:!0}),{delay:i,retryCount:s,shouldRetry:({error:z})=>z instanceof ns});l=!1;let C=_.transactions.find(({from:z,nonce:L})=>z===f.from&&L===f.nonce);if(!C||(p=await $(e,Ii,"getTransactionReceipt")({hash:C.hash}),t>1&&(!p.blockNumber||S-p.blockNumber+1n{b.onReplaced?.({reason:D,replacedTransaction:f,transaction:C,transactionReceipt:p}),b.resolve(p)})}catch(_){k(()=>b.reject(_))}}else k(()=>b.reject(T))}}})});return d}Xe();function Wx(e,{blockTag:t="latest",emitMissed:r=!1,emitOnBegin:n=!1,onBlock:o,onError:s,includeTransactions:i,poll:a,pollingInterval:c=e.pollingInterval}){let u=typeof a<"u"?a:!(e.transport.type==="webSocket"||e.transport.type==="fallback"&&e.transport.transports[0].config.type==="webSocket"),f=i??!1,p;return u?(()=>{let y=ee(["watchBlocks",e.uid,t,r,n,f,c]);return tt(y,{onBlock:o,onError:s},x=>_t(async()=>{try{let m=await $(e,Qe,"getBlock")({blockTag:t,includeTransactions:f});if(m.number&&p?.number){if(m.number===p.number)return;if(m.number-p.number>1&&r)for(let h=p?.number+1n;hp.number)&&(x.onBlock(m,p),p=m)}catch(m){x.onError?.(m)}},{emitOnBegin:n,interval:c}))})():(()=>{let y=!0,x=!0,m=()=>y=!1;return(async()=>{try{n&&$(e,Qe,"getBlock")({blockTag:t,includeTransactions:f}).then(v=>{y&&x&&(o(v,void 0),x=!1)});let h=(()=>{if(e.transport.type==="fallback"){let v=e.transport.transports.find(A=>A.config.type==="webSocket");return v?v.value:e.transport}return e.transport})(),{unsubscribe:b}=await h.subscribe({params:["newHeads"],async onData(v){if(!y)return;let A=await $(e,Qe,"getBlock")({blockNumber:v.blockNumber,includeTransactions:f}).catch(()=>{});y&&(o(A,p),x=!1,p=A)},onError(v){s?.(v)}});m=b,y||m()}catch(h){s?.(h)}})(),()=>m()})()}Xe();Ae();fi();function Kx(e,{address:t,args:r,batch:n=!0,event:o,events:s,fromBlock:i,onError:a,onLogs:c,poll:u,pollingInterval:f=e.pollingInterval,strict:p}){let l=typeof u<"u"?u:typeof i=="bigint"?!0:!(e.transport.type==="webSocket"||e.transport.type==="fallback"&&e.transport.transports[0].config.type==="webSocket"),d=p??!1;return l?(()=>{let m=ee(["watchEvent",t,r,n,e.uid,o,f,i]);return tt(m,{onLogs:c,onError:a},h=>{let b;i!==void 0&&(b=i-1n);let v,A=!1,k=_t(async()=>{if(!A){try{v=await $(e,Su,"createEventFilter")({address:t,args:r,event:o,events:s,strict:d,fromBlock:i})}catch{}A=!0;return}try{let S;if(v)S=await $(e,on,"getFilterChanges")({filter:v});else{let T=await $(e,or,"getBlockNumber")({});b&&b!==T?S=await $(e,ds,"getLogs")({address:t,args:r,event:o,events:s,fromBlock:b+1n,toBlock:T}):S=[],b=T}if(S.length===0)return;if(n)h.onLogs(S);else for(let T of S)h.onLogs([T])}catch(S){v&&S instanceof er&&(A=!1),h.onError?.(S)}},{emitOnBegin:!0,interval:f});return async()=>{v&&await $(e,sn,"uninstallFilter")({filter:v}),k()}})})():(()=>{let m=!0,h=()=>m=!1;return(async()=>{try{let b=(()=>{if(e.transport.type==="fallback"){let S=e.transport.transports.find(T=>T.config.type==="webSocket");return S?S.value:e.transport}return e.transport})(),v=s??(o?[o]:void 0),A=[];v&&(A=[v.flatMap(T=>Xt({abi:[T],eventName:T.name,args:r}))],o&&(A=A[0]));let{unsubscribe:k}=await b.subscribe({params:["logs",{address:t,topics:A}],onData(S){if(!m)return;let T=S.result;try{let{eventName:_,args:C}=fs({abi:v??[],data:T.data,topics:T.topics,strict:d}),D=et(T,{args:C,eventName:_});c([D])}catch(_){let C,D;if(_ instanceof Nt||_ instanceof Vt){if(p)return;C=_.abiItem.name,D=_.abiItem.inputs?.some(L=>!("name"in L&&L.name))}let z=et(T,{args:D?[]:{},eventName:C});c([z])}},onError(S){a?.(S)}});h=k,m||h()}catch(b){a?.(b)}})(),()=>h()})()}Xe();function Yx(e,{batch:t=!0,onError:r,onTransactions:n,poll:o,pollingInterval:s=e.pollingInterval}){return(typeof o<"u"?o:e.transport.type!=="webSocket")?(()=>{let u=ee(["watchPendingTransactions",e.uid,t,s]);return tt(u,{onTransactions:n,onError:r},f=>{let p,l=_t(async()=>{try{if(!p)try{p=await $(e,Iu,"createPendingTransactionFilter")({});return}catch(y){throw l(),y}let d=await $(e,on,"getFilterChanges")({filter:p});if(d.length===0)return;if(t)f.onTransactions(d);else for(let y of d)f.onTransactions([y])}catch(d){f.onError?.(d)}},{emitOnBegin:!0,interval:s});return async()=>{p&&await $(e,sn,"uninstallFilter")({filter:p}),l()}})})():(()=>{let u=!0,f=()=>u=!1;return(async()=>{try{let{unsubscribe:p}=await e.transport.subscribe({params:["newPendingTransactions"],onData(l){if(!u)return;let d=l.result;n([d])},onError(l){r?.(l)}});f=p,u||f()}catch(p){r?.(p)}})(),()=>f()})()}function Zx(e){let{scheme:t,statement:r,...n}=e.match(Zw)?.groups??{},{chainId:o,expirationTime:s,issuedAt:i,notBefore:a,requestId:c,...u}=e.match(Xw)?.groups??{},f=e.split("Resources:")[1]?.split(` +- `).slice(1);return{...n,...u,...o?{chainId:Number(o)}:{},...s?{expirationTime:new Date(s)}:{},...i?{issuedAt:new Date(i)}:{},...a?{notBefore:new Date(a)}:{},...c?{requestId:c}:{},...f?{resources:f}:{},...t?{scheme:t}:{},...r?{statement:r}:{}}}var Zw=/^(?:(?[a-zA-Z][a-zA-Z0-9+-.]*):\/\/)?(?[a-zA-Z0-9+-.]*(?::[0-9]{1,5})?) (?:wants you to sign in with your Ethereum account:\n)(?
0x[a-fA-F0-9]{40})\n\n(?:(?.*)\n\n)?/,Xw=/(?:URI: (?.+))\n(?:Version: (?.+))\n(?:Chain ID: (?\d+))\n(?:Nonce: (?[a-zA-Z0-9]+))\n(?:Issued At: (?.+))(?:\nExpiration Time: (?.+))?(?:\nNot Before: (?.+))?(?:\nRequest ID: (?.+))?/;ps();function Xx(e){let{address:t,domain:r,message:n,nonce:o,scheme:s,time:i=new Date}=e;if(r&&n.domain!==r||o&&n.nonce!==o||s&&n.scheme!==s||n.expirationTime&&i>=n.expirationTime||n.notBefore&&inr(e,t),createAccessList:t=>Tu(e,t),createBlockFilter:()=>Sy(e),createContractEventFilter:t=>ec(e,t),createEventFilter:t=>Su(e,t),createPendingTransactionFilter:()=>Iu(e),estimateContractGas:t=>Uh(e,t),estimateGas:t=>us(e,t),getBalance:t=>Wc(e,t),getBlobBaseFee:()=>Iy(e),getBlock:t=>Qe(e,t),getBlockNumber:t=>or(e,t),getBlockTransactionCount:t=>Py(e,t),getBytecode:t=>ul(e,t),getChainId:()=>Ct(e),getCode:t=>ul(e,t),getContractEvents:t=>Kc(e,t),getEip712Domain:t=>Cy(e,t),getEnsAddress:t=>yy(e,t),getEnsAvatar:t=>Ey(e,t),getEnsName:t=>Ay(e,t),getEnsResolver:t=>Ty(e,t),getEnsText:t=>Au(e,t),getFeeHistory:t=>_y(e,t),estimateFeesPerGas:t=>Rh(e,t),getFilterChanges:t=>on(e,t),getFilterLogs:t=>By(e,t),getGasPrice:()=>os(e),getLogs:t=>ds(e,t),getProof:t=>Xy(e,t),estimateMaxPriorityFeePerGas:t=>Bh(e,t),getStorageAt:t=>Jy(e,t),getTransaction:t=>As(e,t),getTransactionConfirmations:t=>Qy(e,t),getTransactionCount:t=>ss(e,t),getTransactionReceipt:t=>Ii(e,t),multicall:t=>ex(e,t),prepareTransactionRequest:t=>tn(e,t),readContract:t=>Ke(e,t),sendRawTransaction:t=>bs(e,t),simulate:t=>_i(e,t),simulateBlocks:t=>_i(e,t),simulateCalls:t=>Hx(e,t),simulateContract:t=>ry(e,t),verifyMessage:t=>qx(e,t),verifySiweMessage:t=>Jx(e,t),verifyTypedData:t=>Gx(e,t),uninstallFilter:t=>sn(e,t),waitForTransactionReceipt:t=>Vx(e,t),watchBlocks:t=>Wx(e,t),watchBlockNumber:t=>cp(e,t),watchContractEvent:t=>iy(e,t),watchEvent:t=>Kx(e,t),watchPendingTransactions:t=>Yx(e,t)}}function kl(e){let{key:t="public",name:r="Public Client"}=e;return hu({...e,key:t,name:r,type:"publicClient"}).extend(Qx)}V();async function e0(e,{chain:t}){let{id:r,name:n,nativeCurrency:o,rpcUrls:s,blockExplorers:i}=t;await e.request({method:"wallet_addEthereumChain",params:[{chainId:R(r),chainName:n,nativeCurrency:o,rpcUrls:s.default.http,blockExplorerUrls:i?Object.values(i).map(({url:a})=>a):void 0}]},{dedupe:!0,retryCount:0})}tu();function t0(e,t){let{abi:r,args:n,bytecode:o,...s}=t,i=zn({abi:r,args:n,bytecode:o});return gs(e,{...s,...s.authorizationList?{to:null}:{},data:i})}Sn();async function r0(e){return e.account?.type==="local"?[e.account.address]:(await e.request({method:"eth_accounts"},{dedupe:!0})).map(r=>dr(r))}Pe();V();async function n0(e,t={}){let{account:r=e.account,chainId:n}=t,o=r?Z(r):void 0,s=n?[o?.address,[R(n)]]:[o?.address],i=await e.request({method:"wallet_getCapabilities",params:s}),a={};for(let[c,u]of Object.entries(i))a[Number(c)]=u;return typeof n=="number"?a[n]:a}async function o0(e){return await e.request({method:"wallet_getPermissions"},{dedupe:!0})}Pe();ps();async function up(e,t){let{account:r=e.account,chainId:n,nonce:o}=t;if(!r)throw new je({docsPath:"/docs/eip7702/prepareAuthorization"});let s=Z(r),i=(()=>{if(t.executor)return t.executor==="self"?t.executor:Z(t.executor)})(),a={address:t.contractAddress??t.address,chainId:n,nonce:o};return typeof a.chainId>"u"&&(a.chainId=e.chain?.id??await $(e,Ct,"getChainId")({})),typeof a.nonce>"u"&&(a.nonce=await $(e,ss,"getTransactionCount")({address:s.address,blockTag:"pending"}),(i==="self"||i?.address&&rr(i.address,s.address))&&(a.nonce+=1)),a}Sn();async function s0(e){return(await e.request({method:"eth_requestAccounts"},{dedupe:!0,retryCount:0})).map(r=>Xa(r))}async function i0(e,t){return e.request({method:"wallet_requestPermissions",params:[t]},{retryCount:0})}Pe();ht();V();async function a0(e,t){let{account:r=e.account,chain:n=e.chain,forceAtomic:o=!1,id:s,version:i="2.0.0"}=t;if(typeof r>"u")throw new je({docsPath:"/docs/actions/wallet/sendCalls"});let a=r?Z(r):null,c=t.calls.map(u=>{let f=u;return{data:f.abi?be({abi:f.abi,functionName:f.functionName,args:f.args}):f.data,to:f.to,value:f.value?R(f.value):void 0}});try{let u=await e.request({method:"wallet_sendCalls",params:[{atomicRequired:o,calls:c,capabilities:Jw(t.capabilities),chainId:R(n.id),from:a?.address,id:s,version:i}]},{retryCount:0});return typeof u=="string"?{id:u}:u}catch(u){throw pu(u,{...t,account:a,chain:t.chain})}}function Jw(e){let t=e?.paymasterService?Object.entries(e.paymasterService).reduce((r,[n,o])=>({...r??{},[R(Number(n))]:o}),{}):void 0;return{...e,...t?{paymasterService:t}:{}}}async function c0(e,t){let{id:r}=t;await e.request({method:"wallet_showCallsStatus",params:[r]})}Pe();async function u0(e,t){let{account:r=e.account}=t;if(!r)throw new je({docsPath:"/docs/eip7702/signAuthorization"});let n=Z(r);if(!n.signAuthorization)throw new an({docsPath:"/docs/eip7702/signAuthorization",metaMessages:["The `signAuthorization` Action does not support JSON-RPC Accounts."],type:n.type});let o=await up(e,t);return n.signAuthorization(o)}Pe();V();async function p0(e,{account:t=e.account,message:r}){if(!t)throw new je({docsPath:"/docs/actions/wallet/signMessage"});let n=Z(t);if(n.signMessage)return n.signMessage({message:r});let o=typeof r=="string"?Wt(r):r.raw instanceof Uint8Array?M(r.raw):r.raw;return e.request({method:"personal_sign",params:[o,n.address]},{retryCount:0})}Pe();V();Xr();Qr();async function f0(e,t){let{account:r=e.account,chain:n=e.chain,...o}=t;if(!r)throw new je({docsPath:"/docs/actions/wallet/signTransaction"});let s=Z(r);ft({account:s,...t});let i=await $(e,Ct,"getChainId")({});n!==null&&uu({currentChainId:i,chain:n});let c=(n?.formatters||e.chain?.formatters)?.transactionRequest?.format||gt;return s.signTransaction?s.signTransaction({...o,chainId:i},{serializer:e.chain?.serializers?.transaction}):await e.request({method:"eth_signTransaction",params:[{...c(o),chainId:R(i),from:s.address}]},{retryCount:0})}Pe();async function l0(e,t){let{account:r=e.account,domain:n,message:o,primaryType:s}=t;if(!r)throw new je({docsPath:"/docs/actions/wallet/signTypedData"});let i=Z(r),a={EIP712Domain:Ru({domain:n}),...t.types};if(Bu({domain:n,message:o,primaryType:s,types:a}),i.signTypedData)return i.signTypedData({domain:n,message:o,primaryType:s,types:a});let c=My({domain:n,message:o,primaryType:s,types:a});return e.request({method:"eth_signTypedData_v4",params:[i.address,c]},{retryCount:0})}V();async function d0(e,{id:t}){await e.request({method:"wallet_switchEthereumChain",params:[{chainId:R(t)}]},{retryCount:0})}async function m0(e,t){return await e.request({method:"wallet_watchAsset",params:t},{retryCount:0})}function h0(e){return{addChain:t=>e0(e,t),deployContract:t=>t0(e,t),getAddresses:()=>r0(e),getCallsStatus:t=>fu(e,t),getCapabilities:t=>n0(e,t),getChainId:()=>Ct(e),getPermissions:()=>o0(e),prepareAuthorization:t=>up(e,t),prepareTransactionRequest:t=>tn(e,t),requestAddresses:()=>s0(e),requestPermissions:t=>i0(e,t),sendCalls:t=>a0(e,t),sendRawTransaction:t=>bs(e,t),sendTransaction:t=>gs(e,t),showCallsStatus:t=>c0(e,t),signAuthorization:t=>u0(e,t),signMessage:t=>p0(e,t),signTransaction:t=>f0(e,t),signTypedData:t=>l0(e,t),switchChain:t=>d0(e,t),waitForCallsStatus:t=>uy(e,t),watchAsset:t=>m0(e,t),writeContract:t=>ay(e,t)}}function _l(e){let{key:t="wallet",name:r="Wallet Client",transport:n}=e;return hu({...e,key:t,name:r,transport:n,type:"walletClient"}).extend(h0)}ui();var y0={gasPriceOracle:{address:"0x420000000000000000000000000000000000000F"},l1Block:{address:"0x4200000000000000000000000000000000000015"},l2CrossDomainMessenger:{address:"0x4200000000000000000000000000000000000007"},l2Erc721Bridge:{address:"0x4200000000000000000000000000000000000014"},l2StandardBridge:{address:"0x4200000000000000000000000000000000000010"},l2ToL1MessagePasser:{address:"0x4200000000000000000000000000000000000016"}};Mt();At();at();V();function x0(e,t){return ev(e)?Qw(e):jy(e,t)}function Qw(e){tv(e);let{sourceHash:t,data:r,from:n,gas:o,isSystemTx:s,mint:i,to:a,value:c}=e,u=[t,n,a??"0x",i?M(i):"0x",c?M(c):"0x",o?M(o):"0x",s?"0x1":"0x",r??"0x"];return _e(["0x7e",bt(u)])}function ev(e){return e.type==="deposit"||typeof e.sourceHash<"u"}function tv(e){let{from:t,to:r}=e;if(t&&!ie(t))throw new fe({address:t});if(r&&!ie(r))throw new fe({address:r})}var b0={estimateFeesPerGas:async e=>{if(!e.request?.feeCurrency)return null;let[t,r]=await Promise.all([rv(e.client,e.request.feeCurrency),nv(e.client,e.request.feeCurrency)]);return{maxFeePerGas:e.multiply(t-r)+r,maxPriorityFeePerGas:r}}};async function rv(e,t){let r=await e.request({method:"eth_gasPrice",params:[t]});return BigInt(r)}async function nv(e,t){let r=await e.request({method:"eth_maxPriorityFeePerGas",params:[t]});return BigInt(r)}Ve();Xr();En();function Bl(e){return e===0||e===0n||e===void 0||e===null||e==="0"||e===""||typeof e=="string"&&($e(e).toLowerCase()==="0x"||$e(e).toLowerCase()==="0x00")}function _s(e){return!Bl(e)}function ov(e){return typeof e.maxFeePerGas<"u"&&typeof e.maxPriorityFeePerGas<"u"}function pp(e){return e.type==="cip64"?!0:ov(e)&&_s(e.feeCurrency)}var g0={block:_h({format(e){return{transactions:e.transactions?.map(r=>typeof r=="string"?r:{...Un(r),...r.gatewayFee?{gatewayFee:ge(r.gatewayFee),gatewayFeeRecipient:r.gatewayFeeRecipient}:{},feeCurrency:r.feeCurrency}),...e.randomness?{randomness:e.randomness}:{}}}}),transaction:kh({format(e){if(e.type==="0x7e")return{isSystemTx:e.isSystemTx,mint:e.mint?ge(e.mint):void 0,sourceHash:e.sourceHash,type:"deposit"};let t={feeCurrency:e.feeCurrency};return e.type==="0x7b"?t.type="cip64":(e.type==="0x7c"&&(t.type="cip42"),t.gatewayFee=e.gatewayFee?ge(e.gatewayFee):null,t.gatewayFeeRecipient=e.gatewayFeeRecipient),t}}),transactionRequest:Ph({format(e){let t={};return e.feeCurrency&&(t.feeCurrency=e.feeCurrency),pp(e)&&(t.type="0x7b"),t}})};Uc();Mt();Y();ms();Er();At();at();V();function sv(e,t){return pp(e)?iv(e,t):x0(e,t)}var w0={transaction:sv};function iv(e,t){cv(e);let{chainId:r,gas:n,nonce:o,to:s,value:i,maxFeePerGas:a,maxPriorityFeePerGas:c,accessList:u,feeCurrency:f,data:p}=e,l=[M(r),o?M(o):"0x",c?M(c):"0x",a?M(a):"0x",n?M(n):"0x",s??"0x",i?M(i):"0x",p??"0x",Dn(u),f,...pn(e,t)];return _e(["0x7b",bt(l)])}var av=Jr;function cv(e){let{chainId:t,maxPriorityFeePerGas:r,gasPrice:n,maxFeePerGas:o,to:s,feeCurrency:i}=e;if(t<=0)throw new Ar({chainId:t});if(s&&!ie(s))throw new fe({address:s});if(n)throw new g("`gasPrice` is not a valid CIP-64 Transaction attribute.");if(_s(o)&&o>av)throw new pt({maxFeePerGas:o});if(_s(r)&&_s(o)&&r>o)throw new It({maxFeePerGas:o,maxPriorityFeePerGas:r});if(_s(i)&&!ie(i))throw new g("`feeCurrency` MUST be a token address for CIP-64 transactions.");if(Bl(i))throw new g("`feeCurrency` must be provided for CIP-64 transactions.")}var v0={contracts:y0,formatters:g0,serializers:w0,fees:b0};var fp=Ry({...v0,id:42220,name:"Celo",nativeCurrency:{decimals:18,name:"CELO",symbol:"CELO"},rpcUrls:{default:{http:["https://forno.celo.org"]}},blockExplorers:{default:{name:"Celo Explorer",url:"https://celoscan.io",apiUrl:"https://api.celoscan.io/api"}},contracts:{multicall3:{address:"0xcA11bde05977b3631167028862bE2a173976CA11",blockCreated:13112599}},testnet:!1});J0();nb();var Ev=Object.create,ab=Object.defineProperty,Av=Object.getOwnPropertyDescriptor,cb=Object.getOwnPropertyNames,Tv=Object.getPrototypeOf,Sv=Object.prototype.hasOwnProperty,Ll=(e,t)=>function(){return t||(0,e[cb(e)[0]])((t={exports:{}}).exports,t),t.exports},Iv=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of cb(t))!Sv.call(e,o)&&o!==r&&ab(e,o,{get:()=>t[o],enumerable:!(n=Av(t,o))||n.enumerable});return e},Pv=(e,t,r)=>(r=e!=null?Ev(Tv(e)):{},Iv(ab(r,"default",{value:e,enumerable:!0}),e)),Cv=Ll({"../../node_modules/react/cjs/react.production.min.js"(e){var t=Symbol.for("react.element"),r=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),s=Symbol.for("react.profiler"),i=Symbol.for("react.provider"),a=Symbol.for("react.context"),c=Symbol.for("react.forward_ref"),u=Symbol.for("react.suspense"),f=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),l=Symbol.iterator;function d(w){return w===null||typeof w!="object"?null:(w=l&&w[l]||w["@@iterator"],typeof w=="function"?w:null)}var y={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},x=Object.assign,m={};function h(w,P,W){this.props=w,this.context=P,this.refs=m,this.updater=W||y}h.prototype.isReactComponent={},h.prototype.setState=function(w,P){if(typeof w!="object"&&typeof w!="function"&&w!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,w,P,"setState")},h.prototype.forceUpdate=function(w){this.updater.enqueueForceUpdate(this,w,"forceUpdate")};function b(){}b.prototype=h.prototype;function v(w,P,W){this.props=w,this.context=P,this.refs=m,this.updater=W||y}var A=v.prototype=new b;A.constructor=v,x(A,h.prototype),A.isPureReactComponent=!0;var k=Array.isArray,S=Object.prototype.hasOwnProperty,T={current:null},_={key:!0,ref:!0,__self:!0,__source:!0};function C(w,P,W){var J,X={},ye=null,ue=null;if(P!=null)for(J in P.ref!==void 0&&(ue=P.ref),P.key!==void 0&&(ye=""+P.key),P)S.call(P,J)&&!_.hasOwnProperty(J)&&(X[J]=P[J]);var pe=arguments.length-2;if(pe===1)X.children=W;else if(1Bv)throw new Error(`Tick out of bounds: ${e}`);let n=(r&0x1n)!==0n?0xfffcb933bd6fad37aa2d162d1a594001n:0x100000000000000000000000000000000n;return(r&0x2n)!==0n&&(n=n*0xfff97272373d413259a46990580e213an>>128n),(r&0x4n)!==0n&&(n=n*0xfff2e50f5f656932ef12357cf3c7fdccn>>128n),(r&0x8n)!==0n&&(n=n*0xffe5caca7e10e4e61c3624eaa0941cd0n>>128n),(r&0x10n)!==0n&&(n=n*0xffcb9843d60f6159c9db58835c926644n>>128n),(r&0x20n)!==0n&&(n=n*0xff973b41fa98c081472e6896dfb254c0n>>128n),(r&0x40n)!==0n&&(n=n*0xff2ea16466c96a3843ec78b326b52861n>>128n),(r&0x80n)!==0n&&(n=n*0xfe5dee046a99a2a811c461f1969c3053n>>128n),(r&0x100n)!==0n&&(n=n*0xfcbe86c7900a88aedcffc83b479aa3a4n>>128n),(r&0x200n)!==0n&&(n=n*0xf987a7253ac413176f2b074cf7815e54n>>128n),(r&0x400n)!==0n&&(n=n*0xf3392b0822b70005940c7a398e4b70f3n>>128n),(r&0x800n)!==0n&&(n=n*0xe7159475a2c29b7443b29c7fa6e889d9n>>128n),(r&0x1000n)!==0n&&(n=n*0xd097f3bdfd2022b8845ad8f792aa5825n>>128n),(r&0x2000n)!==0n&&(n=n*0xa9f746462d870fdf8a65dc1f90e061e5n>>128n),(r&0x4000n)!==0n&&(n=n*0x70d869a156d2a1b890bb3df62baf32f7n>>128n),(r&0x8000n)!==0n&&(n=n*0x31be135f97d08fd981231505542fcfa6n>>128n),(r&0x10000n)!==0n&&(n=n*0x9aa508b5b7a84e1c677de54f3e99bc9n>>128n),(r&0x20000n)!==0n&&(n=n*0x5d6af8dedb81196699c329225ee604n>>128n),(r&0x40000n)!==0n&&(n=n*0x2216e584f5fa1ea926041bedfe98n>>128n),(r&0x80000n)!==0n&&(n=n*0x48a170391f7dc42444e8fa2n>>128n),t>0n&&(n=Rv/n),(n>>32n)+(n%(1n<<32n)===0n?0n:1n)}function Nv(e,t,r,n){if(e===0n)return{amount0:0n,amount1:0n};let o=zl(t),s=zl(r);if(n=r)return{amount0:0n,amount1:e*(s-o)/Wi};let i=zl(n),a=e*(s-i)*Wi/(i*s),c=e*(i-o)/Wi;return{amount0:a,amount1:c}}function Fv(e){if(e===0n)return 0;let t=e*e*lb/$v,r=Number(gp(t));return r<=0?0:Ye?r:1/r}function Ov(e){if(e===0n)return 0;let t=e*lb/Wi;return Number(gp(t))}function db(e,t,r,n){let o=t,s=vp(r),i=vp(n);return i<=s||o<=s||o>=i?0:e*o*i/(i-o)*(o-s)}function mb(e,t,r,n){let o=t,s=vp(r),i=vp(n);return i<=s||o>=i||o<=s?0:e/(o-s)*(i-o)/(o*i)}function hb(e){return e===0?"0":e.toFixed(6).replace(/\.?0+$/,"")}function yb(e,t,r,n){let o=parseFloat(e);if(isNaN(o)||o<=0||t<=0)return"";let s=Ye?db(o,t,r,n):mb(o,t,r,n);return!isFinite(s)||s<0?"":hb(s)}function xb(e,t,r,n){let o=parseFloat(e);if(isNaN(o)||o<=0||t<=0)return"";let s=Ye?mb(o,t,r,n):db(o,t,r,n);return!isFinite(s)||s<0?"":hb(s)}var Vi=2n**128n-1n,ib=42220,Tp=class{publicClient;walletClient=null;constructor(e,t){if(!e)throw new Error("Public client is required");if(e.chain?.id!==ib)throw new Error("Public client must be connected to Celo mainnet");this.publicClient=e,t&&this.setWalletClient(t)}setWalletClient(e){if(e.chain?.id!==ib)throw new Error("Wallet client must be connected to Celo mainnet");this.walletClient=e}async loadPoolData(){let e=await this.publicClient.readContract({address:Dl,abi:_v,functionName:"slot0"}),t=e[0],r=e[1];return{sqrtPriceX96:t,currentTick:r,gdPriceInUsdglo:Fv(t),sqrtPriceFloat:Ov(t)}}async loadUserBalancesAndAllowances(e){let t=await this.publicClient.multicall({contracts:[{address:Vn,abi:Gi,functionName:"balanceOf",args:[e]},{address:Wn,abi:Gi,functionName:"balanceOf",args:[e]},{address:Vn,abi:Gi,functionName:"allowance",args:[e,ar]},{address:Wn,abi:Gi,functionName:"allowance",args:[e,ar]}]}),r=t[0].status==="success"?t[0].result:0n,n=t[1].status==="success"?t[1].result:0n,o=t[2].status==="success"?t[2].result:0n,s=t[3].status==="success"?t[3].result:0n;return{gdBalance:r,usdgloBalance:n,gdAllowance:o,usdgloAllowance:s}}async getUserPositions(e,t){let r;try{let c=await this.publicClient.readContract({address:ar,abi:Gn,functionName:"balanceOf",args:[e]});r=Number(c)}catch{return[]}if(r===0)return[];let o=(await this.publicClient.multicall({contracts:Array.from({length:r},(c,u)=>({address:ar,abi:Gn,functionName:"tokenOfOwnerByIndex",args:[e,BigInt(u)]}))})).filter(c=>c.status==="success").map(c=>c.result);if(o.length===0)return[];let s=await this.publicClient.multicall({contracts:o.map(c=>({address:ar,abi:Gn,functionName:"positions",args:[c]}))}),i=[];for(let c=0;cthis.publicClient.simulateContract({account:e,address:ar,abi:Gn,functionName:"collect",args:[{tokenId:c.tokenId,recipient:e,amount0Max:Vi,amount1Max:Vi}]}).then(u=>(console.log(u.result),u.result),()=>[c.tokensOwed0,c.tokensOwed1])));return i.map((c,u)=>{let[f,p]=a[u],{amount0:l,amount1:d}=Nv(c.liquidity,c.tickLower,c.tickUpper,t);return{tokenId:c.tokenId,token0:c.token0,token1:c.token1,fee:c.fee,tickLower:c.tickLower,tickUpper:c.tickUpper,liquidity:c.liquidity,tokensOwed0:f,tokensOwed1:p,amount0:l,amount1:d,inRange:t>=c.tickLower&&tsetTimeout(u,2e3)),c}async addLiquidity(e,t,r,n,o){let{account:s,walletClient:i}=await this.requireWallet(),a=Ye?e:t,c=Ye?t:e,u=BigInt(Math.floor(Date.now()/1e3)+1200),{request:f}=await this.publicClient.simulateContract({account:s,address:ar,abi:Gn,functionName:"mint",args:[{token0:ob,token1:sb,fee:wp,tickLower:r,tickUpper:n,amount0Desired:a,amount1Desired:c,amount0Min:0n,amount1Min:0n,recipient:s,deadline:u}]}),p=await i.writeContract(f);return o?.onHash?.(p),await this.publicClient.waitForTransactionReceipt({hash:p}),o?.onConfirmed?.(p),await new Promise(l=>setTimeout(l,2e3)),p}async removeLiquidity(e,t,r){if(t>Vi)throw new Error("Liquidity value exceeds uint128 maximum");let{account:n,walletClient:o}=await this.requireWallet(),s=BigInt(Math.floor(Date.now()/1e3)+1200),{request:i}=await this.publicClient.simulateContract({account:n,address:ar,abi:Gn,functionName:"decreaseLiquidity",args:[{tokenId:e,liquidity:t,amount0Min:0n,amount1Min:0n,deadline:s}]}),a=await o.writeContract(i);return r?.onHash?.(a),await this.publicClient.waitForTransactionReceipt({hash:a}),r?.onConfirmed?.(a),await new Promise(c=>setTimeout(c,2e3)),a}async collectFees(e,t){let{account:r,walletClient:n}=await this.requireWallet(),{request:o}=await this.publicClient.simulateContract({account:r,address:ar,abi:Gn,functionName:"collect",args:[{tokenId:e,recipient:r,amount0Max:Vi,amount1Max:Vi}]}),s=await n.writeContract(o);return t?.onHash?.(s),await this.publicClient.waitForTransactionReceipt({hash:s}),t?.onConfirmed?.(s),await new Promise(i=>setTimeout(i,2e3)),s}static parseTxError(e){let t=e?.message||e?.toString()||"";return t.includes("User rejected")||t.includes("user rejected")||t.includes("ACTION_REJECTED")?"Transaction was rejected in your wallet.":t.includes("insufficient funds")||t.includes("InsufficientFunds")?"Insufficient funds to cover gas fees.":t.includes("exceeds balance")?"Token balance too low for this transaction.":t.includes("UNPREDICTABLE_GAS")||t.includes("execution reverted")?"Transaction would fail on-chain. Try adjusting your amounts.":t.includes("nonce")?"Transaction nonce conflict. Please reset your wallet or wait for pending transactions.":t.length>120?"Transaction failed. Please try again.":t||"Transaction failed. Please try again."}async requireWallet(){if(!this.walletClient)throw new Error("Wallet client not initialized");let[e]=await this.walletClient.getAddresses();if(!e)throw new Error("No account found in wallet client");return{account:e,walletClient:this.walletClient}}},oq=Pv(kv());function Kn(e){try{return!e||e.trim()===""||e==="."?0n:pl(e)}catch{return 0n}}var bb=/^[0-9]*\.?[0-9]*$/;function gb(e){let{gdInput:t,usdgloInput:r,gdBalance:n,usdgloBalance:o,force:s}=e;if(t&&!bb.test(t))return"Invalid G$ value";if(r&&!bb.test(r))return"Invalid USDGLO value";let i=parseFloat(t||"0"),a=parseFloat(r||"0");return s&&(isNaN(i)||i<=0||isNaN(a)||a<=0)?"Please enter valid amounts":i>0&&Kn(t)>n?"Insufficient G$ balance":a>0&&Kn(r)>o?"Insufficient USDGLO balance":null}function wb(e){let{gdWei:t,usdgloWei:r,gdAllowance:n,usdgloAllowance:o}=e,s=t>0n&&n0n&&o? +
${this.text}
+ `}_show(){this._visible=!0}_hide(){this._visible=!1}_toggle(){this._visible=!this._visible}};Zn.styles=Ge` + :host { + display: inline-flex; + position: relative; + vertical-align: middle; + } + + .trigger { + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + border-radius: 50%; + background: #e5e7eb; + color: #6b7280; + font-size: 10px; + font-weight: 700; + line-height: 1; + border: none; + padding: 0; + margin-left: 4px; + transition: background 0.15s; + } + .trigger:hover { background: #d1d5db; } + + .popover { + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + background: #1f2937; + color: #f9fafb; + font-size: 12px; + line-height: 1.5; + padding: 8px 12px; + border-radius: 8px; + width: max-content; + max-width: 260px; + z-index: 100; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + pointer-events: none; + opacity: 0; + transition: opacity 0.15s; + } + + .popover.visible { + opacity: 1; + pointer-events: auto; + } + + .popover::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + border: 6px solid transparent; + border-top-color: #1f2937; + } + `,H([re({type:String})],Zn.prototype,"text",2),H([ve()],Zn.prototype,"_visible",2),Zn=H([Ze("lw-tooltip")],Zn);var Hl=[{id:"full",label:"Full Range",description:"Max flexibility, lower capital efficiency",tooltip:"Covers the entire price range. Your liquidity is always active but spread thin, earning lower fees per dollar deposited.",concentrationMultiplier:1,getTickRange:()=>({tickLower:Ep,tickUpper:Ap})},{id:"wide",label:"Wide",description:"Balanced range around current price",tooltip:"Concentrates liquidity in a wide band around the current price. Good balance of fee earnings and rebalancing frequency.",concentrationMultiplier:4,getTickRange:(e,t)=>({tickLower:Ki(e-120*t,t),tickUpper:Ki(e+120*t,t)})},{id:"narrow",label:"Narrow",description:"Tight range, higher yield, more risk",tooltip:"Concentrates liquidity tightly around the current price for maximum fee earnings. Higher impermanent loss risk and may go out of range if price moves significantly.",concentrationMultiplier:10,getTickRange:(e,t)=>({tickLower:Ki(e-30*t,t),tickUpper:Ki(e+30*t,t)})}],Xn=class extends Ee{constructor(){super(...arguments);this.selected="full";this.baseApr=0}render(){return K` +
+ Range Strategy + +
+
+ ${Hl.map(r=>K` +
this._select(r.id)} + > +
${r.label}
+
${r.description}
+ ${this.baseApr>0?K` +
~${(this.baseApr*r.concentrationMultiplier).toFixed(1)}% APR
+ `:""} +
+ `)} +
+ `}_select(r){this.selected=r,this.dispatchEvent(new CustomEvent("range-change",{detail:{id:r},bubbles:!0,composed:!0}))}};Xn.styles=Ge` + :host { display: block; margin-bottom: 16px; } + + .label { + font-size: 13px; + font-weight: 600; + color: #374151; + margin-bottom: 8px; + display: flex; + align-items: center; + } + + .presets { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + } + + .preset-card { + background: #f9fafb; + border: 2px solid #e5e7eb; + border-radius: 10px; + padding: 10px 8px; + cursor: pointer; + text-align: center; + transition: border-color 0.15s, background 0.15s; + } + .preset-card:hover { border-color: #d1d5db; } + .preset-card.selected { + border-color: var(--lw-primary, #00b0ff); + background: rgba(0, 176, 255, 0.06); + } + + .preset-name { + font-size: 13px; + font-weight: 600; + color: #111827; + margin-bottom: 2px; + } + + .preset-desc { + font-size: 11px; + color: #6b7280; + line-height: 1.3; + margin-bottom: 4px; + } + + .preset-yield { + font-size: 12px; + font-weight: 600; + color: #059669; + } + `,H([re({type:String})],Xn.prototype,"selected",2),H([re({type:Number})],Xn.prototype,"baseApr",2),Xn=H([Ze("lw-range-presets")],Xn);var $s=class extends Ee{constructor(){super(...arguments);this.steps=[]}render(){return K` +
+ ${this.steps.map((r,n)=>K` + ${n>0?K`
`:""} +
+
+ ${r.status==="completed"?K`✓`:r.status==="skipped"?K`—`:K`${n+1}`} +
+ ${r.label} +
+ `)} +
+ `}_connectorDone(r){let n=this.steps[r-1];return n?.status==="completed"||n?.status==="skipped"}};$s.styles=Ge` + :host { display: block; margin-bottom: 16px; } + + .stepper { + display: flex; + align-items: center; + justify-content: center; + gap: 0; + padding: 12px 0; + } + + .step { + display: flex; + align-items: center; + gap: 6px; + font-size: 13px; + color: #9ca3af; + white-space: nowrap; + } + + .step.active { color: var(--lw-primary, #00b0ff); font-weight: 600; } + .step.completed { color: #10b981; } + .step.skipped { color: #d1d5db; text-decoration: line-through; } + + .step-circle { + width: 24px; + height: 24px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + font-weight: 600; + flex-shrink: 0; + border: 2px solid #e5e7eb; + background: white; + color: #9ca3af; + } + + .step.active .step-circle { + border-color: var(--lw-primary, #00b0ff); + background: var(--lw-primary, #00b0ff); + color: white; + } + + .step.completed .step-circle { + border-color: #10b981; + background: #10b981; + color: white; + } + + .step.skipped .step-circle { + border-color: #e5e7eb; + background: #f3f4f6; + color: #d1d5db; + } + + .connector { + width: 32px; + height: 2px; + background: #e5e7eb; + margin: 0 4px; + flex-shrink: 0; + } + + .connector.done { background: #10b981; } + + @keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } + } + .step.active .step-circle { animation: pulse 1.5s ease-in-out infinite; } + `,H([re({type:Array})],$s.prototype,"steps",2),$s=H([Ze("lw-stepper")],$s);var dn=class extends Ee{constructor(){super(...arguments);this.gdPrice=0;this.loading=!1;this.explorerUrl="https://celoscan.io"}render(){let r=`${wp/1e4}%`,n=this.loading?"Loading...":this.gdPrice>0?`${(1e3*this.gdPrice).toFixed(4)} USDGLO`:"...";return K` +
+
+ Pool + + + G$ / USDGLO +
+
+ Fee Tier + ${r} +
+
+ Price (1,000 G$) + ${n} +
+ +
+ `}};dn.styles=Ge` + :host { display: block; margin-bottom: 16px; } + + .pool-info { + background: #f0f9ff; + border: 1px solid #bae6fd; + border-radius: 10px; + padding: 12px 14px; + display: flex; + flex-wrap: wrap; + gap: 12px; + align-items: center; + justify-content: space-between; + } + + .info-item { + display: flex; + flex-direction: column; + gap: 2px; + } + + .info-label { + font-size: 11px; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.03em; + display: flex; + align-items: center; + } + + .info-value { + font-size: 14px; + font-weight: 600; + color: #111827; + } + + .pool-link { + font-size: 12px; + color: var(--lw-primary, #00b0ff); + text-decoration: none; + font-weight: 500; + } + .pool-link:hover { text-decoration: underline; } + `,H([re({type:Number})],dn.prototype,"gdPrice",2),H([re({type:Boolean})],dn.prototype,"loading",2),H([re({type:String})],dn.prototype,"explorerUrl",2),dn=H([Ze("lw-pool-info")],dn);var Ir=class extends Ee{constructor(){super(...arguments);this.phase="idle";this.txHash="";this.errorMessage="";this.explorerUrl="https://celoscan.io"}render(){if(this.phase==="idle")return K``;if(this.phase==="error")return K` +
+ +
+ ${this.errorMessage||"Transaction failed."} +
+ +
+
+ `;if(this.phase==="success")return K` +
+ +
+ Liquidity added successfully! + ${this.txHash?K` +
View on Explorer + `:""} +
+
+ `;let r=this.phase==="approving-gd"?"Approving G$...":this.phase==="approving-usdglo"?"Approving USDGLO...":"Adding liquidity...";return K` +
+
+
+ ${r} + ${this.txHash?K` +
View transaction + `:""} +
+
+ `}_retry(){this.dispatchEvent(new CustomEvent("retry",{bubbles:!0,composed:!0}))}};Ir.styles=Ge` + :host { display: block; margin-bottom: 12px; } + + .status-banner { + border-radius: 10px; + padding: 12px 14px; + font-size: 13px; + line-height: 1.5; + display: flex; + align-items: flex-start; + gap: 10px; + } + + .status-banner.info { + background: #eff6ff; + border: 1px solid #bfdbfe; + color: #1e40af; + } + .status-banner.success { + background: #ecfdf5; + border: 1px solid #a7f3d0; + color: #065f46; + } + .status-banner.error { + background: #fef2f2; + border: 1px solid #fecaca; + color: #991b1b; + } + + .status-icon { font-size: 16px; flex-shrink: 0; margin-top: 1px; } + .status-body { flex: 1; } + .status-body a { + color: inherit; + font-weight: 600; + text-decoration: underline; + } + + .retry-btn { + margin-top: 8px; + background: #991b1b; + color: white; + border: none; + border-radius: 6px; + padding: 6px 14px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + } + .retry-btn:hover { background: #7f1d1d; } + + @keyframes spin { + to { transform: rotate(360deg); } + } + .spinner { + width: 16px; + height: 16px; + border: 2px solid #bfdbfe; + border-top-color: #1e40af; + border-radius: 50%; + animation: spin 0.8s linear infinite; + flex-shrink: 0; + margin-top: 1px; + } + `,H([re({type:String})],Ir.prototype,"phase",2),H([re({type:String})],Ir.prototype,"txHash",2),H([re({type:String})],Ir.prototype,"errorMessage",2),H([re({type:String})],Ir.prototype,"explorerUrl",2),Ir=H([Ze("lw-tx-status")],Ir);var Uv="https://app.ubeswap.org/#/pools",Jn=class extends Ee{constructor(){super(...arguments);this.explorerUrl="https://celoscan.io"}_fmt(r){if(r===0n)return"0";let n=Number(nt(r));return n<1e-4?"<0.0001":n.toLocaleString("en-US",{maximumFractionDigits:4})}render(){let r=this.position;if(!r)return K``;let n=Ye?r.amount0:r.amount1,o=Ye?r.amount1:r.amount0,s=Ye?r.tokensOwed0:r.tokensOwed1,i=Ye?r.tokensOwed1:r.tokensOwed0,a=`${Uv}/${r.tokenId.toString()}`;return K` +
+
+ Position #${r.tokenId.toString()} + + ${r.inRange?"In Range":"Out of Range"} + +
+ +
+
+ G$ + ${this._fmt(n)} +
+
+ USDGLO + ${this._fmt(o)} +
+
+ +
+ Unclaimed Fees + + ${this._fmt(s)} G$ / ${this._fmt(i)} USDGLO + +
+ + +
+ `}};Jn.styles=Ge` + :host { display: block; } + + .card { + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 10px; + padding: 14px; + margin-bottom: 10px; + transition: border-color 0.15s; + } + .card:hover { border-color: #d1d5db; } + + .card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; + } + + .token-id { + font-size: 12px; + color: #6b7280; + font-weight: 500; + } + + .range-badge { + font-size: 11px; + font-weight: 600; + padding: 2px 8px; + border-radius: 12px; + } + .range-badge.in-range { background: #d1fae5; color: #065f46; } + .range-badge.out-of-range { background: #fef3c7; color: #92400e; } + + .amounts { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + margin-bottom: 10px; + } + + .amount-item { + display: flex; + flex-direction: column; + gap: 1px; + } + .amount-label { + font-size: 11px; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.03em; + } + .amount-value { + font-size: 14px; + font-weight: 600; + color: #111827; + } + + .fees-row { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: 8px; + border-top: 1px solid #e5e7eb; + } + .fees-label { + font-size: 12px; + color: #6b7280; + } + .fees-value { + font-size: 13px; + font-weight: 600; + color: #059669; + } + + .actions { + display: flex; + gap: 8px; + margin-top: 10px; + } + + .manage-link { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + border-radius: 8px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + text-decoration: none; + transition: background 0.15s; + background: var(--lw-primary, #00b0ff); + color: white; + } + .manage-link:hover { filter: brightness(0.92); } + .manage-link .arrow { margin-left: 6px; font-size: 14px; } + `,H([re({type:Object})],Jn.prototype,"position",2),H([re({type:String})],Jn.prototype,"explorerUrl",2),Jn=H([Ze("lw-position-card")],Jn);var mn=class extends Ee{constructor(){super(...arguments);this.positions=[];this.loading=!1;this.explorerUrl="https://celoscan.io"}_fmt(r){let n=Number(nt(r));if(n===0)return"0";let o=n<10?4:n<100?2:1;return Intl.NumberFormat(void 0,{maximumFractionDigits:o}).format(n)}render(){if(this.loading)return K`
Loading positions...
`;let r=this.positions.reduce((i,a)=>i+(Ye?a.amount0:a.amount1),0n),n=this.positions.reduce((i,a)=>i+(Ye?a.amount1:a.amount0),0n),o=this.positions.reduce((i,a)=>i+(Ye?a.tokensOwed0:a.tokensOwed1),0n),s=this.positions.reduce((i,a)=>i+(Ye?a.tokensOwed1:a.tokensOwed0),0n);return K` +
+ + My Positions + + ${this.positions.length>0?K`${this.positions.length}`:""} + +
+ + ${this.positions.length===0?K` +
No open positions in this pool.
+ `:K` +
+
+ Total G$ + ${this._fmt(r)} +
+
+ Total USDGLO + ${this._fmt(n)} +
+
+ Unclaimed Fees + ${this._fmt(o)} G$ / ${this._fmt(s)} GLO +
+
+ + ${this.positions.map(i=>K` + + `)} + `} + `}};mn.styles=Ge` + :host { display: block; } + + .header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 14px; + } + + .header-title { + font-size: 16px; + font-weight: 600; + color: #111827; + display: flex; + align-items: center; + } + + .count-badge { + font-size: 11px; + font-weight: 600; + background: var(--lw-primary, #00b0ff); + color: white; + border-radius: 10px; + padding: 1px 7px; + margin-left: 8px; + } + + .summary { + background: #f0fdf4; + border: 1px solid #bbf7d0; + border-radius: 10px; + padding: 12px 14px; + margin-bottom: 14px; + display: flex; + gap: 16px; + flex-wrap: wrap; + } + + .summary-item { + display: flex; + flex-direction: column; + gap: 1px; + } + .summary-label { font-size: 11px; color: #6b7280; text-transform: uppercase; letter-spacing: 0.03em; } + .summary-value { font-size: 14px; font-weight: 600; color: #065f46; } + + .empty { + text-align: center; + color: #9ca3af; + font-size: 14px; + padding: 24px 0; + } + + .loading { + text-align: center; + color: #6b7280; + font-size: 14px; + padding: 24px 0; + } + `,H([re({type:Array})],mn.prototype,"positions",2),H([re({type:Boolean})],mn.prototype,"loading",2),H([re({type:String})],mn.prototype,"explorerUrl",2),mn=H([Ze("lw-positions-panel")],mn);var oe=class extends Ee{constructor(){super(...arguments);this.web3Provider=null;this.connectWallet=void 0;this.explorerBaseUrl=pb;this.approvalBuffer=fb;this.defaultRange="full";this.showPositions=!0;this.theme=void 0;this.refreshInterval=3e4;this.activeTab="add";this.gdInput="";this.usdgloInput="";this.gdBalance=0n;this.usdgloBalance=0n;this.gdAllowance=0n;this.usdgloAllowance=0n;this.poolData=null;this.currentTick=0;this.isLoading=!1;this.inputError="";this.selectedRange="full";this.tickLower=Ep;this.tickUpper=Ap;this.txPhase="idle";this.txHash="";this.txError="";this.txSteps=[];this.positions=[];this.positionsLoading=!1;this.walletClient=null;this.publicClient=null;this.sdk=null;this.userAddress=null;this._refreshTimer=null}connectedCallback(){super.connectedCallback(),this.selectedRange=this.defaultRange,this.refreshData()}disconnectedCallback(){super.disconnectedCallback(),this._stopRefreshTimer()}updated(r){r.has("web3Provider")&&this.refreshData(),r.has("refreshInterval")&&this._syncRefreshTimer(),r.has("theme")&&this._applyTheme()}get _isConnected(){return!!(this.web3Provider&&this.web3Provider.isConnected&&this.userAddress)}_syncRefreshTimer(){this._stopRefreshTimer(),this._isConnected&&this.refreshInterval>0&&(this._refreshTimer=setInterval(()=>this.refreshData(),this.refreshInterval))}_stopRefreshTimer(){this._refreshTimer&&(clearInterval(this._refreshTimer),this._refreshTimer=null)}_fmt(r){return r===0n?"0":Number(nt(r)).toLocaleString("en-US",{maximumFractionDigits:2})}render(){let r=!!(this.web3Provider&&this.web3Provider.isConnected&&this.userAddress),n=this.poolData?.gdPriceInUsdglo??0;return K` +
+ +
+ +
+

G$ / USDGLO Liquidity

+ +
+
+ + + + + + ${this.showPositions&&r?K` +
+ + +
+ `:we} + + + ${this.activeTab==="add"?this._renderAddTab(r):this._renderPositionsTab()} + + ${this.txPhase!=="idle"&&this.txPhase!=="success"&&this.txPhase!=="error"?K`
`:we} +
+ `}_renderAddTab(r){let n=this.txPhase!=="idle"&&this.txSteps.length>0;return K` + + + + +
+
+ + G$ + + + + Balance: ${this.isLoading?"Loading...":this._fmt(this.gdBalance)} + +
+
+ + +
+
+ + +
+
+ + USDGLO + + + + Balance: ${this.isLoading?"Loading...":this._fmt(this.usdgloBalance)} + +
+
+ + +
+
+ + ${this.inputError?K`
${this.inputError}
`:we} + + + + + + ${n?K``:we} + + + ${r?K` + + `:K``} + `}_renderPositionsTab(){return K` + + `}_applyTheme(){this.theme&&(this.theme.primaryColor&&this.style.setProperty("--lw-primary",this.theme.primaryColor),this.theme.borderRadius&&this.style.setProperty("--lw-radius",this.theme.borderRadius),this.theme.fontFamily&&this.style.setProperty("--lw-font",this.theme.fontFamily))}_ensureSDK(){return this.publicClient||(this.publicClient=kl({chain:fp,transport:il()})),this.sdk||(this.sdk=new Tp(this.publicClient)),this.walletClient&&this.sdk.setWalletClient(this.walletClient),this.sdk}async refreshData(){let r=this._ensureSDK();if(r){this.isLoading=!0;try{let n=await r.loadPoolData();this.poolData=n,this.currentTick=n.currentTick}catch(n){console.error("Error loading pool data:",n)}try{if(this.web3Provider&&this.web3Provider.isConnected){this.walletClient=_l({chain:fp,transport:ol(this.web3Provider)}),r.setWalletClient(this.walletClient);let n=await this.web3Provider.request({method:"eth_accounts"});if(n.length>0){this.userAddress=n[0];let o=await r.loadUserBalancesAndAllowances(this.userAddress);this.gdBalance=o.gdBalance,this.usdgloBalance=o.usdgloBalance,this.gdAllowance=o.gdAllowance,this.usdgloAllowance=o.usdgloAllowance}else this._resetUserData()}else this._resetUserData()}catch(n){console.error("Error loading user data:",n)}this.isLoading=!1,this._syncRefreshTimer()}}_resetUserData(){this.userAddress=null,this.gdBalance=0n,this.usdgloBalance=0n,this.gdAllowance=0n,this.usdgloAllowance=0n,this.positions=[]}async _loadPositions(){let r=this.sdk;if(!(!r||!this.userAddress)){this.positionsLoading=!0;try{this.positions=await r.getUserPositions(this.userAddress,this.currentTick)}catch(n){console.error("Error loading positions:",n)}this.positionsLoading=!1}}_validateInputs(r=!1){this.inputError=gb({gdInput:this.gdInput,usdgloInput:this.usdgloInput,gdBalance:this.gdBalance,usdgloBalance:this.usdgloBalance,force:r})??""}_getButtonLabel(){if(this.txPhase==="success")return"Add More Liquidity";let r=Kn(this.gdInput),n=Kn(this.usdgloInput);return r>0n&&this.gdAllowance0n&&this.usdgloAllowancea.id===n),{tickLower:s,tickUpper:i}=o.getTickRange(this.currentTick,ub);this.tickLower=s,this.tickUpper=i,this._syncUsdgloFromGd()}_handleRetry(){this.txPhase="idle",this.txHash="",this.txError="",this.txSteps=[]}async _handleMainAction(){let r=this.sdk;if(!r||!this.walletClient||!this.userAddress)return;if(this.txPhase==="success"){this.txPhase="idle",this.txHash="",this.txSteps=[];return}if(this._validateInputs(!0),this.inputError)return;let n=Kn(this.gdInput),o=Kn(this.usdgloInput),{steps:s,needGdApproval:i,needUsdgloApproval:a}=wb({gdWei:n,usdgloWei:o,gdAllowance:this.gdAllowance,usdgloAllowance:this.usdgloAllowance}),c=s;this.txSteps=c,this.txError="";try{if(i){this.txPhase="approving-gd",this.txHash="",this.txSteps=Yn(c,0,{status:"active"});let f=await r.approveToken(Vn,n,this.approvalBuffer,{onHash:p=>{this.txHash=p,this._emitTxEvent("lw-tx-submitted",p,"approve-gd")},onConfirmed:p=>this._emitTxEvent("lw-tx-confirmed",p,"approve-gd")});this.txSteps=c=Yn(c,0,{status:"completed",txHash:f}),await this.refreshData()}if(a){this.txPhase="approving-usdglo",this.txHash="",this.txSteps=Yn(c,1,{status:"active"});let f=await r.approveToken(Wn,o,this.approvalBuffer,{onHash:p=>{this.txHash=p,this._emitTxEvent("lw-tx-submitted",p,"approve-usdglo")},onConfirmed:p=>this._emitTxEvent("lw-tx-confirmed",p,"approve-usdglo")});this.txSteps=c=Yn(c,1,{status:"completed",txHash:f}),await this.refreshData()}this.txPhase="minting",this.txHash="",this.txSteps=Yn(c,2,{status:"active"});let u=await r.addLiquidity(n,o,this.tickLower,this.tickUpper,{onHash:f=>{this.txHash=f,this._emitTxEvent("lw-tx-submitted",f,"mint")},onConfirmed:f=>this._emitTxEvent("lw-tx-confirmed",f,"mint")});this.txSteps=Yn(c,2,{status:"completed",txHash:u}),this.txPhase="success",this.txHash=u,this._emitEvent("lw-position-added",{hash:u}),this.gdInput="",this.usdgloInput="",this.inputError="",await this.refreshData()}catch(u){this.txPhase="error",this.txError=Tp.parseTxError(u),this._emitTxEvent("lw-tx-failed",this.txHash,this.txPhase,u)}}_emitEvent(r,n){this.dispatchEvent(new CustomEvent(r,{detail:n,bubbles:!0,composed:!0}))}_emitTxEvent(r,n,o,s){this._emitEvent(r,{hash:n,step:o,...s?{error:Tp.parseTxError(s)}:{}})}};oe.styles=Ge` + :host { + display: block; + font-family: var(--lw-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif); + max-width: 480px; + margin: 0 auto; + } + + .container { + background: white; + border-radius: var(--lw-radius, 16px); + padding: 24px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + border: 1px solid #e5e7eb; + position: relative; + } + + .header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 8px; + } + + .logo { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; } + .logo img { width: 44px; height: 44px; box-shadow: rgba(0,0,0,0.075) 0px 6px 10px; border-radius: 50%; background: white; } + + .title { font-size: 20px; font-weight: 600; color: #111827; margin: 0; flex: 1; } + .title-row { display: flex; align-items: center; gap: 4px; } + + /* Tabs */ + .tabs { + display: flex; + background: #f3f4f6; + border-radius: 10px; + padding: 3px; + margin-bottom: 16px; + } + .tab { + flex: 1; + text-align: center; + padding: 8px 0; + font-size: 14px; + font-weight: 600; + color: #6b7280; + border-radius: 8px; + border: none; + background: transparent; + cursor: pointer; + transition: all 0.15s; + } + .tab.active { background: white; color: #111827; box-shadow: 0 1px 2px rgba(0,0,0,0.06); } + .tab:hover:not(.active) { color: #374151; } + + /* Input sections */ + .input-section { + background: #f9fafb; + border-radius: 12px; + padding: 16px; + margin-bottom: 12px; + border: 1px solid #e5e7eb; + } + .input-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } + .token-name { font-size: 15px; font-weight: 600; color: #111827; display: flex; align-items: center; } + .balance-info { font-size: 13px; color: #6b7280; } + .input-container { display: flex; align-items: center; gap: 12px; } + .amount-input { + flex: 1; border: none; background: transparent; + font-size: 22px; font-weight: 600; color: #111827; outline: none; + min-width: 0; + } + .max-button { + background: #fff; border-radius: 8px; padding: 5px 10px; + font-size: 12px; font-weight: 500; color: #374151; + border: 1px solid #d1d5db; cursor: pointer; transition: all 0.15s; + } + .max-button:hover { border-color: var(--lw-primary, #00b0ff); color: var(--lw-primary, #00b0ff); } + + /* Buttons */ + .main-button { + width: 100%; + background: var(--lw-primary, #00b0ff); + border: none; + border-radius: 12px; + padding: 14px; + font-size: 16px; + font-weight: 600; + color: #fff; + cursor: pointer; + transition: background 0.15s; + box-shadow: rgba(11,27,102,0.2) 2px 2px 8px -1px; + } + .main-button:hover { filter: brightness(0.92); } + .main-button:disabled { opacity: 0.55; cursor: not-allowed; filter: none; } + + .error-message { color: #dc2626; font-size: 12px; margin-bottom: 12px; text-align: center; } + .hidden { display: none; } + + .overlay { + position: absolute; inset: 0; + background: rgba(255,255,255,0.3); + border-radius: var(--lw-radius, 16px); + z-index: 10; + pointer-events: none; + } + `,H([re({type:Object})],oe.prototype,"web3Provider",2),H([re({type:Function})],oe.prototype,"connectWallet",2),H([re({type:String})],oe.prototype,"explorerBaseUrl",2),H([re({type:Number})],oe.prototype,"approvalBuffer",2),H([re({type:String})],oe.prototype,"defaultRange",2),H([re({type:Boolean})],oe.prototype,"showPositions",2),H([re({type:Object})],oe.prototype,"theme",2),H([re({type:Number})],oe.prototype,"refreshInterval",2),H([ve()],oe.prototype,"activeTab",2),H([ve()],oe.prototype,"gdInput",2),H([ve()],oe.prototype,"usdgloInput",2),H([ve()],oe.prototype,"gdBalance",2),H([ve()],oe.prototype,"usdgloBalance",2),H([ve()],oe.prototype,"gdAllowance",2),H([ve()],oe.prototype,"usdgloAllowance",2),H([ve()],oe.prototype,"poolData",2),H([ve()],oe.prototype,"currentTick",2),H([ve()],oe.prototype,"isLoading",2),H([ve()],oe.prototype,"inputError",2),H([ve()],oe.prototype,"selectedRange",2),H([ve()],oe.prototype,"tickLower",2),H([ve()],oe.prototype,"tickUpper",2),H([ve()],oe.prototype,"txPhase",2),H([ve()],oe.prototype,"txHash",2),H([ve()],oe.prototype,"txError",2),H([ve()],oe.prototype,"txSteps",2),H([ve()],oe.prototype,"positions",2),H([ve()],oe.prototype,"positionsLoading",2),oe=H([Ze("gooddollar-liquidity-widget")],oe);return Tb(Mv);})(); +/*! Bundled license information: + +react/cjs/react.production.min.js: + (** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react/cjs/react.development.js: + (** + * @license React + * react.development.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) +*/ +/*! Bundled license information: + +@noble/hashes/esm/utils.js: + (*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@noble/curves/esm/abstract/utils.js: + (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@noble/curves/esm/abstract/modular.js: + (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@noble/curves/esm/abstract/curve.js: + (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@noble/curves/esm/abstract/weierstrass.js: + (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@noble/curves/esm/_shortw_utils.js: + (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@noble/curves/esm/secp256k1.js: + (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) + +@lit/reactive-element/css-tag.js: + (** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/reactive-element.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +lit-html/lit-html.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +lit-element/lit-element.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +lit-html/is-server.js: + (** + * @license + * Copyright 2022 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/custom-element.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/property.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/state.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/event-options.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/base.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/query.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/query-all.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/query-async.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/query-assigned-elements.js: + (** + * @license + * Copyright 2021 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@lit/reactive-element/decorators/query-assigned-nodes.js: + (** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + *) + +@noble/hashes/esm/utils.js: + (*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *) +*/