diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..47e64770 --- /dev/null +++ b/.npmrc @@ -0,0 +1,7 @@ +# Disable git operations during npm install to prevent issues in CI/CD environments +# This fixes the git config error during Cloudflare Pages deployment +unsafe-perm=true +ignore-scripts=false + +# Configure git to use system config only +git-tag-version=false diff --git a/Builders codes/fetch_builder_data.js b/Builders codes/fetch_builder_data.js new file mode 100644 index 00000000..c5a68c00 --- /dev/null +++ b/Builders codes/fetch_builder_data.js @@ -0,0 +1,118 @@ +const https = require('https'); +const fs = require('fs'); +const lz4js = require('lz4js'); + +const builderAddress = '0x5e1d081488a5e746c1a13bf92103c1b9ee5962a2'; +// 2026-01-12 is today. Let's check 12, 11, 10. +const dates = ['20260112', '20260111', '20260110', '20260109']; + +async function fetchAndProcess(date) { + const url = `https://stats-data.hyperliquid.xyz/Mainnet/builder_fills/${builderAddress}/${date}.csv.lz4`; + // console.log(`Fetching ${url}...`); + + return new Promise((resolve) => { + https.get(url, (res) => { + if (res.statusCode !== 200) { + // console.log(`No data for ${date} (Status: ${res.statusCode})`); + resolve(null); + return; + } + + const chunks = []; + res.on('data', chunk => chunks.push(chunk)); + res.on('end', () => { + const buffer = Buffer.concat(chunks); + try { + const decompressed = lz4js.decompress(buffer); + const csv = Buffer.from(decompressed).toString('utf8'); + resolve({ date, csv }); + } catch (e) { + console.error(`Error decompressing ${date}:`, e.message); + resolve(null); + } + }); + res.on('error', () => resolve(null)); + }); + }); +} + +function parseCSV(csv) { + const lines = csv.trim().split('\n'); + const headers = lines[0].split(','); + const data = []; + for (let i = 1; i < lines.length; i++) { + const values = lines[i].split(','); + const row = {}; + headers.forEach((h, index) => { + row[h] = values[index]; + }); + data.push(row); + } + return data; +} + +async function main() { + const results = []; + for (const date of dates) { + const result = await fetchAndProcess(date); + if (result) { + results.push(result); + } + } + + if (results.length === 0) { + console.log("No builder referral data found for the last 3-4 days."); + return; + } + + console.log("Builder Code Referrals (Last available data):"); + let totalFees = 0; + const uniqueUsers = new Set(); + const dailyStats = {}; + + results.forEach(({ date, csv }) => { + const records = parseCSV(csv); + let dailyFees = 0; + let dailyUsers = new Set(); + + records.forEach(r => { + const fee = parseFloat(r.builder_fee || 0); + dailyFees += fee; + totalFees += fee; + if (r.user) { + uniqueUsers.add(r.user); + dailyUsers.add(r.user); + } + }); + + dailyStats[date] = { + fees: dailyFees, + users: dailyUsers.size, + transactions: records.length + }; + }); + + console.table(dailyStats); + console.log(`\nTotal Builder Fees: ${totalFees.toFixed(6)} USDC`); + console.log(`Total Unique Users: ${uniqueUsers.size}`); + + console.log("\nUser Breakdown:"); + const userBreakdown = {}; + results.forEach(({ csv }) => { + const records = parseCSV(csv); + records.forEach(r => { + if (r.user) { + if (!userBreakdown[r.user]) { + userBreakdown[r.user] = 0; + } + userBreakdown[r.user] += parseFloat(r.builder_fee || 0); + } + }); + }); + + Object.entries(userBreakdown).forEach(([user, fee]) => { + console.log(`User: ${user}, Total Fee: ${fee.toFixed(6)} USDC`); + }); +} + +main(); diff --git a/Builders codes/node_modules/.package-lock.json b/Builders codes/node_modules/.package-lock.json new file mode 100644 index 00000000..2632ac8d --- /dev/null +++ b/Builders codes/node_modules/.package-lock.json @@ -0,0 +1,14 @@ +{ + "name": "builder-codes-fetcher", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/lz4js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/lz4js/-/lz4js-0.2.0.tgz", + "integrity": "sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg==", + "license": "ISC" + } + } +} diff --git a/Builders codes/node_modules/lz4js/.eslintrc b/Builders codes/node_modules/lz4js/.eslintrc new file mode 100644 index 00000000..c147bfff --- /dev/null +++ b/Builders codes/node_modules/lz4js/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "semistandard" +} diff --git a/Builders codes/node_modules/lz4js/.npmignore b/Builders codes/node_modules/lz4js/.npmignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/Builders codes/node_modules/lz4js/.npmignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/Builders codes/node_modules/lz4js/.travis.yml b/Builders codes/node_modules/lz4js/.travis.yml new file mode 100644 index 00000000..f2badf90 --- /dev/null +++ b/Builders codes/node_modules/lz4js/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: + - "6.0" + - "4.1" + - "0.12" + - "0.10" +before_script: + - "npm install codecov.io istanbul" +script: + - "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec test/cases && cat ./coverage/coverage.json | ./node_modules/codecov.io/bin/codecov.io.js" \ No newline at end of file diff --git a/Builders codes/node_modules/lz4js/README.md b/Builders codes/node_modules/lz4js/README.md new file mode 100644 index 00000000..2da39985 --- /dev/null +++ b/Builders codes/node_modules/lz4js/README.md @@ -0,0 +1,39 @@ +# Lz4.js [![NPM version](https://badge.fury.io/js/lz4js.svg)](https://www.npmjs.com/package/lz4js) [![Build Status](https://travis-ci.org/Benzinga/lz4js.svg?branch=master)](https://travis-ci.org/Benzinga/lz4js) [![codecov](https://codecov.io/gh/Benzinga/lz4js/branch/master/graph/badge.svg)](https://codecov.io/gh/Benzinga/lz4js) +Lz4.js is an implementation of Lz4 designed to be used in web browsers. It contains no dependencies on external libraries or Node.JS, though it is organized as a set of CommonJS modules. It is recommended to use Browserify or WebPack to bundle this for the web browser. + +## Installation +``` +npm install lz4js +``` + +## Usage +```javascript +var lz4 = require("lz4js"); +var fs = require("fs"); + +// Compress 128 bytes of zero. +var compressed = lz4.compress(new Array(128)); + +// Decompress. +var decompressed = lz4.decompress(compressed); + +// Compress file.bin to file.lz4. +var data = fs.readFileSync("file.bin"); +compressed = Buffer.from(lz4.compress(data)); +fs.writeFileSync('file.lz4', compressed); +``` + +> **Note**: The high-level `compress` and `decompress` functions deal with framed Lz4 data and do not support raw block data nor legacy Lz4 blocks. + +## API +The API accepts either `Array`s or `Uint8Array`s. Arrays are expected to be arrays of unsigned 8-bit values. The API will return `Uint8Array`s if the browser supports them, or `Array`s otherwise. + + - `compress(buffer: Array, maxSize: Number): Array` + + Compresses a buffer using Lz4. maxSize sets bounds on the output length; it is recommended to not specify this unless you know what you're doing. + Any unused buffer data will be sliced before the buffer is returned. + + - `decompress(buffer: Array, maxSize: Number): Array` + + Decompresses a buffer using Lz4. maxSize sets bounds on the output length; if you know the output length, this will reduce memory usage somewhat. + Any unused buffer data will be sliced before the buffer is returned. diff --git a/Builders codes/node_modules/lz4js/lz4.js b/Builders codes/node_modules/lz4js/lz4.js new file mode 100644 index 00000000..821dbb6f --- /dev/null +++ b/Builders codes/node_modules/lz4js/lz4.js @@ -0,0 +1,560 @@ +// lz4.js - An implementation of Lz4 in plain JavaScript. +// +// TODO: +// - Unify header parsing/writing. +// - Support options (block size, checksums) +// - Support streams +// - Better error handling (handle bad offset, etc.) +// - HC support (better search algorithm) +// - Tests/benchmarking + +var xxhash = require('./xxh32.js'); +var util = require('./util.js'); + +// Constants +// -- + +// Compression format parameters/constants. +var minMatch = 4; +var minLength = 13; +var searchLimit = 5; +var skipTrigger = 6; +var hashSize = 1 << 16; + +// Token constants. +var mlBits = 4; +var mlMask = (1 << mlBits) - 1; +var runBits = 4; +var runMask = (1 << runBits) - 1; + +// Shared buffers +var blockBuf = makeBuffer(5 << 20); +var hashTable = makeHashTable(); + +// Frame constants. +var magicNum = 0x184D2204; + +// Frame descriptor flags. +var fdContentChksum = 0x4; +var fdContentSize = 0x8; +var fdBlockChksum = 0x10; +// var fdBlockIndep = 0x20; +var fdVersion = 0x40; +var fdVersionMask = 0xC0; + +// Block sizes. +var bsUncompressed = 0x80000000; +var bsDefault = 7; +var bsShift = 4; +var bsMask = 7; +var bsMap = { + 4: 0x10000, + 5: 0x40000, + 6: 0x100000, + 7: 0x400000 +}; + +// Utility functions/primitives +// -- + +// Makes our hashtable. On older browsers, may return a plain array. +function makeHashTable () { + try { + return new Uint32Array(hashSize); + } catch (error) { + var hashTable = new Array(hashSize); + + for (var i = 0; i < hashSize; i++) { + hashTable[i] = 0; + } + + return hashTable; + } +} + +// Clear hashtable. +function clearHashTable (table) { + for (var i = 0; i < hashSize; i++) { + hashTable[i] = 0; + } +} + +// Makes a byte buffer. On older browsers, may return a plain array. +function makeBuffer (size) { + try { + return new Uint8Array(size); + } catch (error) { + var buf = new Array(size); + + for (var i = 0; i < size; i++) { + buf[i] = 0; + } + + return buf; + } +} + +function sliceArray (array, start, end) { + if (typeof array.buffer !== undefined) { + if (Uint8Array.prototype.slice) { + return array.slice(start, end); + } else { + // Uint8Array#slice polyfill. + var len = array.length; + + // Calculate start. + start = start | 0; + start = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len); + + // Calculate end. + end = (end === undefined) ? len : end | 0; + end = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len); + + // Copy into new array. + var arraySlice = new Uint8Array(end - start); + for (var i = start, n = 0; i < end;) { + arraySlice[n++] = array[i++]; + } + + return arraySlice; + } + } else { + // Assume normal array. + return array.slice(start, end); + } +} + +// Implementation +// -- + +// Calculates an upper bound for lz4 compression. +exports.compressBound = function compressBound (n) { + return (n + (n / 255) + 16) | 0; +}; + +// Calculates an upper bound for lz4 decompression, by reading the data. +exports.decompressBound = function decompressBound (src) { + var sIndex = 0; + + // Read magic number + if (util.readU32(src, sIndex) !== magicNum) { + throw new Error('invalid magic number'); + } + + sIndex += 4; + + // Read descriptor + var descriptor = src[sIndex++]; + + // Check version + if ((descriptor & fdVersionMask) !== fdVersion) { + throw new Error('incompatible descriptor version ' + (descriptor & fdVersionMask)); + } + + // Read flags + var useBlockSum = (descriptor & fdBlockChksum) !== 0; + var useContentSize = (descriptor & fdContentSize) !== 0; + + // Read block size + var bsIdx = (src[sIndex++] >> bsShift) & bsMask; + + if (bsMap[bsIdx] === undefined) { + throw new Error('invalid block size ' + bsIdx); + } + + var maxBlockSize = bsMap[bsIdx]; + + // Get content size + if (useContentSize) { + return util.readU64(src, sIndex); + } + + // Checksum + sIndex++; + + // Read blocks. + var maxSize = 0; + while (true) { + var blockSize = util.readU32(src, sIndex); + sIndex += 4; + + if (blockSize & bsUncompressed) { + blockSize &= ~bsUncompressed; + maxSize += blockSize; + } else { + maxSize += maxBlockSize; + } + + if (blockSize === 0) { + return maxSize; + } + + if (useBlockSum) { + sIndex += 4; + } + + sIndex += blockSize; + } +}; + +// Creates a buffer of a given byte-size, falling back to plain arrays. +exports.makeBuffer = makeBuffer; + +// Decompresses a block of Lz4. +exports.decompressBlock = function decompressBlock (src, dst, sIndex, sLength, dIndex) { + var mLength, mOffset, sEnd, n, i; + + // Setup initial state. + sEnd = sIndex + sLength; + + // Consume entire input block. + while (sIndex < sEnd) { + var token = src[sIndex++]; + + // Copy literals. + var literalCount = (token >> 4); + if (literalCount > 0) { + // Parse length. + if (literalCount === 0xf) { + while (true) { + literalCount += src[sIndex]; + if (src[sIndex++] !== 0xff) { + break; + } + } + } + + // Copy literals + for (n = sIndex + literalCount; sIndex < n;) { + dst[dIndex++] = src[sIndex++]; + } + } + + if (sIndex >= sEnd) { + break; + } + + // Copy match. + mLength = (token & 0xf); + + // Parse offset. + mOffset = src[sIndex++] | (src[sIndex++] << 8); + + // Parse length. + if (mLength === 0xf) { + while (true) { + mLength += src[sIndex]; + if (src[sIndex++] !== 0xff) { + break; + } + } + } + + mLength += minMatch; + + // Copy match. + for (i = dIndex - mOffset, n = i + mLength; i < n;) { + dst[dIndex++] = dst[i++] | 0; + } + } + + return dIndex; +}; + +// Compresses a block with Lz4. +exports.compressBlock = function compressBlock (src, dst, sIndex, sLength, hashTable) { + var mIndex, mAnchor, mLength, mOffset, mStep; + var literalCount, dIndex, sEnd, n; + + // Setup initial state. + dIndex = 0; + sEnd = sLength + sIndex; + mAnchor = sIndex; + + // Process only if block is large enough. + if (sLength >= minLength) { + var searchMatchCount = (1 << skipTrigger) + 3; + + // Consume until last n literals (Lz4 spec limitation.) + while (sIndex + minMatch < sEnd - searchLimit) { + var seq = util.readU32(src, sIndex); + var hash = util.hashU32(seq) >>> 0; + + // Crush hash to 16 bits. + hash = ((hash >> 16) ^ hash) >>> 0 & 0xffff; + + // Look for a match in the hashtable. NOTE: remove one; see below. + mIndex = hashTable[hash] - 1; + + // Put pos in hash table. NOTE: add one so that zero = invalid. + hashTable[hash] = sIndex + 1; + + // Determine if there is a match (within range.) + if (mIndex < 0 || ((sIndex - mIndex) >>> 16) > 0 || util.readU32(src, mIndex) !== seq) { + mStep = searchMatchCount++ >> skipTrigger; + sIndex += mStep; + continue; + } + + searchMatchCount = (1 << skipTrigger) + 3; + + // Calculate literal count and offset. + literalCount = sIndex - mAnchor; + mOffset = sIndex - mIndex; + + // We've already matched one word, so get that out of the way. + sIndex += minMatch; + mIndex += minMatch; + + // Determine match length. + // N.B.: mLength does not include minMatch, Lz4 adds it back + // in decoding. + mLength = sIndex; + while (sIndex < sEnd - searchLimit && src[sIndex] === src[mIndex]) { + sIndex++; + mIndex++; + } + mLength = sIndex - mLength; + + // Write token + literal count. + var token = mLength < mlMask ? mLength : mlMask; + if (literalCount >= runMask) { + dst[dIndex++] = (runMask << mlBits) + token; + for (n = literalCount - runMask; n >= 0xff; n -= 0xff) { + dst[dIndex++] = 0xff; + } + dst[dIndex++] = n; + } else { + dst[dIndex++] = (literalCount << mlBits) + token; + } + + // Write literals. + for (var i = 0; i < literalCount; i++) { + dst[dIndex++] = src[mAnchor + i]; + } + + // Write offset. + dst[dIndex++] = mOffset; + dst[dIndex++] = (mOffset >> 8); + + // Write match length. + if (mLength >= mlMask) { + for (n = mLength - mlMask; n >= 0xff; n -= 0xff) { + dst[dIndex++] = 0xff; + } + dst[dIndex++] = n; + } + + // Move the anchor. + mAnchor = sIndex; + } + } + + // Nothing was encoded. + if (mAnchor === 0) { + return 0; + } + + // Write remaining literals. + // Write literal token+count. + literalCount = sEnd - mAnchor; + if (literalCount >= runMask) { + dst[dIndex++] = (runMask << mlBits); + for (n = literalCount - runMask; n >= 0xff; n -= 0xff) { + dst[dIndex++] = 0xff; + } + dst[dIndex++] = n; + } else { + dst[dIndex++] = (literalCount << mlBits); + } + + // Write literals. + sIndex = mAnchor; + while (sIndex < sEnd) { + dst[dIndex++] = src[sIndex++]; + } + + return dIndex; +}; + +// Decompresses a frame of Lz4 data. +exports.decompressFrame = function decompressFrame (src, dst) { + var useBlockSum, useContentSum, useContentSize, descriptor; + var sIndex = 0; + var dIndex = 0; + + // Read magic number + if (util.readU32(src, sIndex) !== magicNum) { + throw new Error('invalid magic number'); + } + + sIndex += 4; + + // Read descriptor + descriptor = src[sIndex++]; + + // Check version + if ((descriptor & fdVersionMask) !== fdVersion) { + throw new Error('incompatible descriptor version'); + } + + // Read flags + useBlockSum = (descriptor & fdBlockChksum) !== 0; + useContentSum = (descriptor & fdContentChksum) !== 0; + useContentSize = (descriptor & fdContentSize) !== 0; + + // Read block size + var bsIdx = (src[sIndex++] >> bsShift) & bsMask; + + if (bsMap[bsIdx] === undefined) { + throw new Error('invalid block size'); + } + + if (useContentSize) { + // TODO: read content size + sIndex += 8; + } + + sIndex++; + + // Read blocks. + while (true) { + var compSize; + + compSize = util.readU32(src, sIndex); + sIndex += 4; + + if (compSize === 0) { + break; + } + + if (useBlockSum) { + // TODO: read block checksum + sIndex += 4; + } + + // Check if block is compressed + if ((compSize & bsUncompressed) !== 0) { + // Mask off the 'uncompressed' bit + compSize &= ~bsUncompressed; + + // Copy uncompressed data into destination buffer. + for (var j = 0; j < compSize; j++) { + dst[dIndex++] = src[sIndex++]; + } + } else { + // Decompress into blockBuf + dIndex = exports.decompressBlock(src, dst, sIndex, compSize, dIndex); + sIndex += compSize; + } + } + + if (useContentSum) { + // TODO: read content checksum + sIndex += 4; + } + + return dIndex; +}; + +// Compresses data to an Lz4 frame. +exports.compressFrame = function compressFrame (src, dst) { + var dIndex = 0; + + // Write magic number. + util.writeU32(dst, dIndex, magicNum); + dIndex += 4; + + // Descriptor flags. + dst[dIndex++] = fdVersion; + dst[dIndex++] = bsDefault << bsShift; + + // Descriptor checksum. + dst[dIndex] = xxhash.hash(0, dst, 4, dIndex - 4) >> 8; + dIndex++; + + // Write blocks. + var maxBlockSize = bsMap[bsDefault]; + var remaining = src.length; + var sIndex = 0; + + // Clear the hashtable. + clearHashTable(hashTable); + + // Split input into blocks and write. + while (remaining > 0) { + var compSize = 0; + var blockSize = remaining > maxBlockSize ? maxBlockSize : remaining; + + compSize = exports.compressBlock(src, blockBuf, sIndex, blockSize, hashTable); + + if (compSize > blockSize || compSize === 0) { + // Output uncompressed. + util.writeU32(dst, dIndex, 0x80000000 | blockSize); + dIndex += 4; + + for (var z = sIndex + blockSize; sIndex < z;) { + dst[dIndex++] = src[sIndex++]; + } + + remaining -= blockSize; + } else { + // Output compressed. + util.writeU32(dst, dIndex, compSize); + dIndex += 4; + + for (var j = 0; j < compSize;) { + dst[dIndex++] = blockBuf[j++]; + } + + sIndex += blockSize; + remaining -= blockSize; + } + } + + // Write blank end block. + util.writeU32(dst, dIndex, 0); + dIndex += 4; + + return dIndex; +}; + +// Decompresses a buffer containing an Lz4 frame. maxSize is optional; if not +// provided, a maximum size will be determined by examining the data. The +// buffer returned will always be perfectly-sized. +exports.decompress = function decompress (src, maxSize) { + var dst, size; + + if (maxSize === undefined) { + maxSize = exports.decompressBound(src); + } + + dst = exports.makeBuffer(maxSize); + size = exports.decompressFrame(src, dst); + + if (size !== maxSize) { + dst = sliceArray(dst, 0, size); + } + + return dst; +}; + +// Compresses a buffer to an Lz4 frame. maxSize is optional; if not provided, +// a buffer will be created based on the theoretical worst output size for a +// given input size. The buffer returned will always be perfectly-sized. +exports.compress = function compress (src, maxSize) { + var dst, size; + + if (maxSize === undefined) { + maxSize = exports.compressBound(src.length); + } + + dst = exports.makeBuffer(maxSize); + size = exports.compressFrame(src, dst); + + if (size !== maxSize) { + dst = sliceArray(dst, 0, size); + } + + return dst; +}; diff --git a/Builders codes/node_modules/lz4js/package.json b/Builders codes/node_modules/lz4js/package.json new file mode 100644 index 00000000..e31d1709 --- /dev/null +++ b/Builders codes/node_modules/lz4js/package.json @@ -0,0 +1,36 @@ +{ + "name": "lz4js", + "version": "0.2.0", + "description": "An Lz4 implementation for the browser.", + "main": "lz4.js", + "scripts": { + "test": "mocha -R spec test/cases" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/Benzinga/lz4js.git" + }, + "keywords": [ + "lz4", + "compression", + "decompression", + "browser", + "commonjs" + ], + "author": "John Chadwick", + "license": "ISC", + "bugs": { + "url": "https://github.com/Benzinga/lz4js/issues" + }, + "homepage": "https://github.com/Benzinga/lz4js#readme", + "devDependencies": { + "chai": "^3.5.0", + "eslint": "^3.0.1", + "eslint-config-semistandard": "^6.0.2", + "eslint-config-standard": "^5.3.5", + "eslint-plugin-promise": "^2.0.0", + "eslint-plugin-react": "^5.2.2", + "eslint-plugin-standard": "^2.0.0", + "mocha": "^2.5.3" + } +} diff --git a/Builders codes/node_modules/lz4js/test/cases/lz4.js b/Builders codes/node_modules/lz4js/test/cases/lz4.js new file mode 100644 index 00000000..b24e03f3 --- /dev/null +++ b/Builders codes/node_modules/lz4js/test/cases/lz4.js @@ -0,0 +1,268 @@ +/* eslint-env node, mocha */ +var expect = require('chai').expect; +var lz4 = require('../../lz4'); + +// Find root object (depends on JS environment) +var root; +if (typeof window !== 'undefined') { + root = window; +} else if (typeof global !== 'undefined') { + root = global; +} + +// Use plain old arrays for older browsers and older Node. +function byteArray (arg) { + if (root.Uint8Array) { + return new Uint8Array(arg); + } else { + if (typeof arg === 'number' || typeof arg === 'undefined') { + return new Array(arg); + } else { + return arg; + } + } +} + +describe('lz4', function () { + describe('#decompress', function () { + it('should decompress empty lz4 Array correctly', function () { + var emptyLz4 = [4, 34, 77, 24, 64, 112, 223, 0, 0, 0, 0]; + expect(lz4.decompress(emptyLz4)).to.be.deep.equal(byteArray(0)); + }); + + it('should decompress empty lz4 Uint8Array correctly', function () { + var emptyLz4 = byteArray([4, 34, 77, 24, 64, 112, 223, 0, 0, 0, 0]); + expect(lz4.decompress(emptyLz4)).to.be.deep.equal(byteArray(0)); + }); + + it('should decompress data compressed with lz4c', function () { + var output = byteArray([ + 0x54, 0x68, 0x65, 0x20, 0x77, 0x68, 0x6f, 0x6c, + 0x65, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, + 0x69, 0x73, 0x20, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x2e, 0x0a + ]); + var input = byteArray([ + 0x04, 0x22, 0x4d, 0x18, 0x64, 0x40, 0xa7, 0x1b, + 0x00, 0x00, 0x80, 0x54, 0x68, 0x65, 0x20, 0x77, + 0x68, 0x6f, 0x6c, 0x65, 0x20, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0xbc, 0xa8, 0x6b, 0xc5 + ]); + expect(lz4.decompress(input)).to.be.deep.equal(output); + }); + + it('should decompress data compressed with lz4c (2)', function () { + var output = byteArray([ + 0x49, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, + 0x72, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x20, 0x79, + 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x69, 0x74, + 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x61, 0x6b, + 0x65, 0x0a, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x70, 0x65, 0x6f, 0x70, 0x6c, + 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x69, 0x72, + 0x63, 0x6c, 0x65, 0x73, 0x0a, 0x49, 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x2c, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6d, + 0x61, 0x64, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x6d, 0x61, + 0x64, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a + ]); + var input = byteArray([ + 0x04, 0x22, 0x4d, 0x18, 0x64, 0x40, 0xa7, 0x67, 0x00, 0x00, 0x00, 0xff, + 0x0c, 0x49, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x68, + 0x61, 0x72, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x20, + 0x79, 0x6f, 0x75, 0x0a, 0x1b, 0x00, 0x00, 0xf1, 0x1c, 0x61, 0x6b, 0x65, + 0x0a, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x70, 0x65, 0x6f, 0x70, 0x6c, 0x65, + 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x69, 0x72, 0x63, + 0x6c, 0x65, 0x73, 0x0a, 0x49, 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x2c, 0x06, 0x00, 0xf0, 0x07, 0x20, 0x6d, 0x61, 0x64, + 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x6d, 0x61, 0x64, 0x20, + 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2a, + 0xaf, 0xb9 + ]); + expect(lz4.decompress(input)).to.be.deep.equal(output); + }); + + it('should decompress data containing content-size', function () { + var output = byteArray([ + 0x49, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x22, + 0x77, 0x69, 0x6e, 0x2c, 0x22, 0x20, 0x79, 0x6f, + 0x75, 0x20, 0x77, 0x6f, 0x6e, 0x27, 0x74, 0x20, + 0x77, 0x61, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, + 0x22, 0x70, 0x6c, 0x61, 0x79, 0x22, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x6d, 0x65, 0x20, 0x61, + 0x6e, 0x79, 0x6d, 0x6f, 0x72, 0x65, 0x2e, 0x0a + ]); + var input = byteArray([ + 0x04, 0x22, 0x4d, 0x18, 0x6c, 0x40, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x38, + 0x00, 0x00, 0x80, 0x49, 0x66, 0x20, 0x79, 0x6f, + 0x75, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x2c, 0x22, + 0x20, 0x79, 0x6f, 0x75, 0x20, 0x77, 0x6f, 0x6e, + 0x27, 0x74, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, + 0x74, 0x6f, 0x20, 0x22, 0x70, 0x6c, 0x61, 0x79, + 0x22, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6d, + 0x65, 0x20, 0x61, 0x6e, 0x79, 0x6d, 0x6f, 0x72, + 0x65, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x9f, + 0xda, 0xad, 0x19 + ]); + expect(lz4.decompress(input)).to.be.deep.equal(output); + }); + + it('should fail on bad header magic', function () { + var input = byteArray([5, 34, 77, 24, 64, 112, 223, 0, 0, 0, 0]); + var fn = function () { return lz4.decompress(input); }; + expect(fn).to.throw(/invalid magic number/); + }); + + it('should fail on bad block size', function () { + var input = byteArray([4, 34, 77, 24, 64, 0, 223, 0, 0, 0, 0]); + var fn = function () { return lz4.decompress(input); }; + expect(fn).to.throw(/invalid block size/); + }); + }); + + describe('#decompressBlock', function () { + it('should pass the Linux kernel lz4 test vector', function () { + // This test comes from the Linux kernel, crypto/testmgr.h. + // It is the string, "Join us now and share the software ", + // repeated twice. It is probably quoting Richard Stallman's + // "Free Software Song." Lz4 is used in the Linux kernel to + // compress kernel images. + var linuxTestIn = byteArray([ + 0xf0, 0x10, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, + 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, + 0x77, 0x0d, 0x00, 0x0f, 0x23, 0x00, 0x0b, 0x50, + 0x77, 0x61, 0x72, 0x65, 0x20 + ]); + var linuxTestOut = byteArray([ + 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x20, + 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x20, 0x4a, 0x6f, 0x69, 0x6e, 0x20, + 0x75, 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, + 0x74, 0x77, 0x61, 0x72, 0x65, 0x20 + ]); + var testOut = byteArray(70); + + lz4.decompressBlock(linuxTestIn, testOut, 0, 45, 0); + expect(testOut).to.be.deep.equal(linuxTestOut); + }); + }); + + describe('#compress', function () { + it('should compress empty Array correctly', function () { + var emptyLz4 = byteArray([4, 34, 77, 24, 64, 112, 223, 0, 0, 0, 0]); + expect(lz4.compress([])).to.be.deep.equal(emptyLz4); + }); + + it('should compress empty Uint8Array correctly', function () { + var emptyLz4 = byteArray([4, 34, 77, 24, 64, 112, 223, 0, 0, 0, 0]); + expect(lz4.compress(byteArray(0))).to.be.deep.equal(emptyLz4); + }); + + it('should output pseudo RLE', function () { + var input = byteArray([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]); + var output = byteArray([ + 0x04, 0x22, 0x4D, 0x18, 0x40, 0x70, 0xDF, 0x0B, + 0x00, 0x00, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x07, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + ]); + expect(lz4.compress(input)).to.be.deep.equal(output); + }); + + it('should find matches', function () { + var input = byteArray([ + 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74 + ]); + + // Psuedo-RLE describes when the length is greater than the offset, + // i.e. the match goes beyond the cursor. This seems like non-sense, but + // it works because this only occurs if there's a repeating pattern that + // repeats _before_ the cursor - the match matches itself. + var output = byteArray([ + 0x04, 0x22, 0x4d, 0x18, 0x40, 0x70, 0xDF, 0x0E, + 0x00, 0x00, 0x00, 0x4F, 0x74, 0x65, 0x73, 0x74, + 0x04, 0x00, 0x04, 0x50, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x00, 0x00, 0x00, 0x00 + ]); + + expect(lz4.compress(input)).to.be.deep.equal(output); + }); + + it('should use maxSize', function () { + var emptyLz4 = byteArray([4, 34, 77, 24, 64, 112, 223, 0]); + expect(lz4.compress([], 8)).to.be.deep.equal(emptyLz4); + }); + + it('should not compress uncompressible data', function () { + var input = byteArray([ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F + ]); + + // Make note of the 0x80000020 frame size - that last bit marks it + // as being uncompressed. + var output = byteArray([ + 0x04, 0x22, 0x4d, 0x18, 0x40, 0x70, 0xdf, 0x20, + 0x00, 0x00, 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, 0x00, 0x00, 0x00, 0x00 + ]); + + expect(lz4.compress(input)).to.be.deep.equal(output); + }); + }); + + describe('#compressBlock', function () { + it('should be able to output over 15 literals at end', function () { + var input = byteArray([ + 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x20, + 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x20, 0x4a, 0x6f, 0x69, 0x6e, 0x20, + 0x75, 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, + 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 + ]); + var output = byteArray([ + 0xf0, 0x10, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, + 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, + 0x77, 0x0d, 0x00, 0x0f, 0x23, 0x00, 0x10, 0xf0, + 0x03, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18 + ]); + var testOut = byteArray(59); + var sz; + + sz = lz4.compressBlock(input, testOut, 0, input.length, lz4.makeBuffer(1 << 16)); + + expect(sz).to.be.equal(59); + expect(testOut).to.be.deep.equal(output); + }); + }); +}); diff --git a/Builders codes/node_modules/lz4js/test/cases/xxh32.js b/Builders codes/node_modules/lz4js/test/cases/xxh32.js new file mode 100644 index 00000000..e9ee6d67 --- /dev/null +++ b/Builders codes/node_modules/lz4js/test/cases/xxh32.js @@ -0,0 +1,94 @@ +/* eslint-env node, mocha */ +var expect = require('chai').expect; +var xxh32 = require('../../xxh32'); + +describe('xxh32', function () { + describe('#hash', function () { + it('passes the github.com/pierrec/xxHash tests', function () { + var tests = [ + [0x02cc5d05, []], + [0x550d7456, [0x61]], + [0x4999fc53, [0x61, 0x62]], + [0x32d153ff, [0x61, 0x62, 0x63]], + [0xa3643705, [0x61, 0x62, 0x63, 0x64]], + [0x9738f19b, [0x61, 0x62, 0x63, 0x64, 0x65]], + [0x8b7cd587, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66]], + [0x9dd093b3, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67]], + [0x0bb3c6bb, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]], + [0xd03c13fd, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69]], + [0x8b988cfe, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a]], + [0x9d2d8b62, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70]], + [0x42ae804d, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, + 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39]], + [0x62b4ed00, [0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, + 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, + 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, + 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, + 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, + 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2c, + 0x20, 0x73, 0x65, 0x64, 0x20, 0x64, 0x6f, 0x20, + 0x65, 0x69, 0x75, 0x73, 0x6d, 0x6f, 0x64, 0x20, + 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x20, 0x69, + 0x6e, 0x63, 0x69, 0x64, 0x69, 0x64, 0x75, 0x6e, + 0x74, 0x20, 0x75, 0x74, 0x20, 0x6c, 0x61, 0x62, + 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, + 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, + 0x67, 0x6e, 0x61, 0x20, 0x61, 0x6c, 0x69, 0x71, + 0x75, 0x61, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, + 0x6e, 0x69, 0x6d, 0x20, 0x61, 0x64, 0x20, 0x6d, + 0x69, 0x6e, 0x69, 0x6d, 0x20, 0x76, 0x65, 0x6e, + 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, + 0x73, 0x20, 0x6e, 0x6f, 0x73, 0x74, 0x72, 0x75, + 0x64, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, + 0x6c, 0x6c, 0x61, 0x6d, 0x63, 0x6f, 0x20, 0x6c, + 0x61, 0x62, 0x6f, 0x72, 0x69, 0x73, 0x20, 0x6e, + 0x69, 0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, + 0x6c, 0x69, 0x71, 0x75, 0x69, 0x70, 0x20, 0x65, + 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x63, 0x6f, 0x6e, + 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x2e, 0x20, + 0x44, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75, 0x74, + 0x65, 0x20, 0x69, 0x72, 0x75, 0x72, 0x65, 0x20, + 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x69, 0x6e, + 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x69, + 0x6e, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, + 0x61, 0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, + 0x74, 0x20, 0x65, 0x73, 0x73, 0x65, 0x20, 0x63, + 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x64, 0x6f, + 0x6c, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x75, 0x20, + 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x6e, + 0x75, 0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, + 0x69, 0x61, 0x74, 0x75, 0x72, 0x2e, 0x20, 0x45, + 0x78, 0x63, 0x65, 0x70, 0x74, 0x65, 0x75, 0x72, + 0x20, 0x73, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x63, + 0x63, 0x61, 0x65, 0x63, 0x61, 0x74, 0x20, 0x63, + 0x75, 0x70, 0x69, 0x64, 0x61, 0x74, 0x61, 0x74, + 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x6f, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x73, + 0x75, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x63, + 0x75, 0x6c, 0x70, 0x61, 0x20, 0x71, 0x75, 0x69, + 0x20, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x69, 0x61, + 0x20, 0x64, 0x65, 0x73, 0x65, 0x72, 0x75, 0x6e, + 0x74, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x74, + 0x20, 0x61, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x64, + 0x20, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x61, 0x62, + 0x6f, 0x72, 0x75, 0x6d, 0x2e]] + ]; + + for (var i = 0; i < tests.length; ++i) { + var expected = tests[i][0]; + var vector = tests[i][1]; + expect(xxh32.hash(0, vector, 0, vector.length)).to.be.equal(expected); + } + }); + }); +}); diff --git a/Builders codes/node_modules/lz4js/util.js b/Builders codes/node_modules/lz4js/util.js new file mode 100644 index 00000000..80367948 --- /dev/null +++ b/Builders codes/node_modules/lz4js/util.js @@ -0,0 +1,54 @@ +// Simple hash function, from: http://burtleburtle.net/bob/hash/integer.html. +// Chosen because it doesn't use multiply and achieves full avalanche. +exports.hashU32 = function hashU32 (a) { + a = a | 0; + a = a + 2127912214 + (a << 12) | 0; + a = a ^ -949894596 ^ a >>> 19; + a = a + 374761393 + (a << 5) | 0; + a = a + -744332180 ^ a << 9; + a = a + -42973499 + (a << 3) | 0; + return a ^ -1252372727 ^ a >>> 16 | 0; +}; + +// Reads a 64-bit little-endian integer from an array. +exports.readU64 = function readU64 (b, n) { + var x = 0; + x |= b[n++] << 0; + x |= b[n++] << 8; + x |= b[n++] << 16; + x |= b[n++] << 24; + x |= b[n++] << 32; + x |= b[n++] << 40; + x |= b[n++] << 48; + x |= b[n++] << 56; + return x; +}; + +// Reads a 32-bit little-endian integer from an array. +exports.readU32 = function readU32 (b, n) { + var x = 0; + x |= b[n++] << 0; + x |= b[n++] << 8; + x |= b[n++] << 16; + x |= b[n++] << 24; + return x; +}; + +// Writes a 32-bit little-endian integer from an array. +exports.writeU32 = function writeU32 (b, n, x) { + b[n++] = (x >> 0) & 0xff; + b[n++] = (x >> 8) & 0xff; + b[n++] = (x >> 16) & 0xff; + b[n++] = (x >> 24) & 0xff; +}; + +// Multiplies two numbers using 32-bit integer multiplication. +// Algorithm from Emscripten. +exports.imul = function imul (a, b) { + var ah = a >>> 16; + var al = a & 65535; + var bh = b >>> 16; + var bl = b & 65535; + + return al * bl + (ah * bl + al * bh << 16) | 0; +}; diff --git a/Builders codes/node_modules/lz4js/xxh32.js b/Builders codes/node_modules/lz4js/xxh32.js new file mode 100644 index 00000000..0800f533 --- /dev/null +++ b/Builders codes/node_modules/lz4js/xxh32.js @@ -0,0 +1,102 @@ +// xxh32.js - implementation of xxhash32 in plain JavaScript +var util = require('./util.js'); + +// xxhash32 primes +var prime1 = 0x9e3779b1; +var prime2 = 0x85ebca77; +var prime3 = 0xc2b2ae3d; +var prime4 = 0x27d4eb2f; +var prime5 = 0x165667b1; + +// Utility functions/primitives +// -- + +function rotl32 (x, r) { + x = x | 0; + r = r | 0; + + return x >>> (32 - r | 0) | x << r | 0; +} + +function rotmul32 (h, r, m) { + h = h | 0; + r = r | 0; + m = m | 0; + + return util.imul(h >>> (32 - r | 0) | h << r, m) | 0; +} + +function shiftxor32 (h, s) { + h = h | 0; + s = s | 0; + + return h >>> s ^ h | 0; +} + +// Implementation +// -- + +function xxhapply (h, src, m0, s, m1) { + return rotmul32(util.imul(src, m0) + h, s, m1); +} + +function xxh1 (h, src, index) { + return rotmul32((h + util.imul(src[index], prime5)), 11, prime1); +} + +function xxh4 (h, src, index) { + return xxhapply(h, util.readU32(src, index), prime3, 17, prime4); +} + +function xxh16 (h, src, index) { + return [ + xxhapply(h[0], util.readU32(src, index + 0), prime2, 13, prime1), + xxhapply(h[1], util.readU32(src, index + 4), prime2, 13, prime1), + xxhapply(h[2], util.readU32(src, index + 8), prime2, 13, prime1), + xxhapply(h[3], util.readU32(src, index + 12), prime2, 13, prime1) + ]; +} + +function xxh32 (seed, src, index, len) { + var h, l; + l = len; + if (len >= 16) { + h = [ + seed + prime1 + prime2, + seed + prime2, + seed, + seed - prime1 + ]; + + while (len >= 16) { + h = xxh16(h, src, index); + + index += 16; + len -= 16; + } + + h = rotl32(h[0], 1) + rotl32(h[1], 7) + rotl32(h[2], 12) + rotl32(h[3], 18) + l; + } else { + h = (seed + prime5 + len) >>> 0; + } + + while (len >= 4) { + h = xxh4(h, src, index); + + index += 4; + len -= 4; + } + + while (len > 0) { + h = xxh1(h, src, index); + + index++; + len--; + } + + h = shiftxor32(util.imul(shiftxor32(util.imul(shiftxor32(h, 15), prime2), 13), prime3), 16); + + return h >>> 0; +} + +exports.hash = xxh32; diff --git a/Builders codes/package-lock.json b/Builders codes/package-lock.json new file mode 100644 index 00000000..06693d0e --- /dev/null +++ b/Builders codes/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "builder-codes-fetcher", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "builder-codes-fetcher", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "lz4js": "^0.2.0" + } + }, + "node_modules/lz4js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/lz4js/-/lz4js-0.2.0.tgz", + "integrity": "sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg==", + "license": "ISC" + } + } +} diff --git a/Builders codes/package.json b/Builders codes/package.json new file mode 100644 index 00000000..41d7545a --- /dev/null +++ b/Builders codes/package.json @@ -0,0 +1,15 @@ +{ + "name": "builder-codes-fetcher", + "version": "1.0.0", + "description": "Fetch builder codes", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "lz4js": "^0.2.0" + } +} diff --git a/Builders codes/verify_referrals.js b/Builders codes/verify_referrals.js new file mode 100644 index 00000000..71926877 --- /dev/null +++ b/Builders codes/verify_referrals.js @@ -0,0 +1,38 @@ +const https = require('https'); + +const data = JSON.stringify({ + type: "userFunding", + user: "0x5e1D081488a5e746c1a13Bf92103C1B9eE5962A2" +}); + +const options = { + hostname: 'api.hyperliquid.xyz', + port: 443, + path: '/info', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': data.length + } +}; + +const req = https.request(options, (res) => { + let body = ''; + res.on('data', (chunk) => body += chunk); + res.on('end', () => { + // console.log(body); + const parsed = JSON.parse(body); + console.log(formatOutput(parsed)); + }); +}); + +function formatOutput(data) { + return JSON.stringify(data, null, 2); +} + +req.on('error', (error) => { + console.error(error); +}); + +req.write(data); +req.end(); diff --git a/index.html b/index.html index 687fb165..e824529c 100644 --- a/index.html +++ b/index.html @@ -44,7 +44,7 @@ - + = 16 || ^19.0.0-rc" } }, + "node_modules/@hookform/resolvers": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz", + "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -9050,6 +9066,45 @@ "node": ">=4.0" } }, + "node_modules/@nktkas/hyperliquid": { + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/@nktkas/hyperliquid/-/hyperliquid-0.30.2.tgz", + "integrity": "sha512-xz1/oGRunLxY1z1FOsCsXUFOWx8ADL3vL87pQkpl68gIxHT6Duf5z18uxFQWxlPPyB5PHYmpudlziJ6xVPB4Vw==", + "license": "MIT", + "dependencies": { + "@nktkas/rews": "^1.2.3", + "@noble/hashes": "^2.0.1", + "micro-eth-signer": "^0.18.1", + "valibot": "1.2.0" + }, + "bin": { + "hyperliquid": "esm/bin/cli.js" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@nktkas/hyperliquid/node_modules/@noble/hashes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nktkas/rews": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@nktkas/rews/-/rews-1.2.3.tgz", + "integrity": "sha512-cpfcIlkUpYlbAI1cvfCTBCajWZfUM6gWyuCJXszECKxdetsU3vURKC8Sz//MDR6RWoULk9T48eJ+0agxT7yB1w==", + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@noble/ciphers": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", @@ -9427,21 +9482,21 @@ "license": "MIT" }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.8.15.tgz", - "integrity": "sha512-eO3lcZvXwkcBZqpV+7InlzbLddP/wIJjaqbzlyCJAb0PfQ6fY40etiVpK38eFEDX1WGEYOvhKVO6aMgZtaO2lg==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.8.16.tgz", + "integrity": "sha512-EleChIVOXa8qylNCcllByP+AYIoktDmPGfavi3Fn4eWWXoc4wlfL58NEiETbCyi1ZgUtaZUfIUiMvwgjJ4+mwQ==", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-pay": "1.8.15", - "@reown/appkit-polyfills": "1.8.15", - "@reown/appkit-scaffold-ui": "1.8.15", - "@reown/appkit-ui": "1.8.15", - "@reown/appkit-utils": "1.8.15", - "@reown/appkit-wallet": "1.8.15", - "@walletconnect/universal-provider": "2.23.0", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-pay": "1.8.16", + "@reown/appkit-polyfills": "1.8.16", + "@reown/appkit-scaffold-ui": "1.8.16", + "@reown/appkit-ui": "1.8.16", + "@reown/appkit-utils": "1.8.16", + "@reown/appkit-wallet": "1.8.16", + "@walletconnect/universal-provider": "2.23.1", "bs58": "6.0.0", "semver": "7.7.2", "valtio": "2.1.7", @@ -9452,9 +9507,9 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit-common": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.15.tgz", - "integrity": "sha512-swDeGli08KQWB2nkFB5a61IEAfaM5AeDwp5inzlsfW1lHOwS5uO052nacr6wQCCKEp9aWojdEScwnk3qiVFNjQ==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.16.tgz", + "integrity": "sha512-og7EkTEI+mxTEEK3cRoX2PJqgij/5t9CJeN/2dnOef8mEiNh0vAPmdzZPXw9v4oVeBsu14jb8n/Y7vIbTOwl6Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "big.js": "6.2.2", @@ -9463,55 +9518,56 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit-polyfills": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.15.tgz", - "integrity": "sha512-IDq57jf/a//meerJ7Zl7TG9jxpiQ3dJexv68SlzWWUow0DtDd0TMgykofUq5gzBLZBoFexbHyPZih/ylhScVPg==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.16.tgz", + "integrity": "sha512-6ArFDoIbI/DHHCdOCSnh7THP4OvhG5XKKgXbCKSNOuj3/RPl3OmmoFJwwf+LvZJ4ggaz7I6qoXFHf8fEEx1FcQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "buffer": "6.0.3" } }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit-scaffold-ui": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.8.15.tgz", - "integrity": "sha512-fqsVbeoJfiTAAGYOkYzm3T//5HKgtX4gSa3GgYdw7nlJeEYEWtw59z3tZV2Wc0+ym+MhLQNsOBO+pllF6oBFgw==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.8.16.tgz", + "integrity": "sha512-OzTtxwLkE2RcJh4ai87DpXz1zM7twZOpFA6OKWVXPCe2BASLzXWtKmpW8XA6gpA54oEmG4PtoBW9ogv/Qd2e8Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-ui": "1.8.15", - "@reown/appkit-utils": "1.8.15", - "@reown/appkit-wallet": "1.8.15", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-pay": "1.8.16", + "@reown/appkit-ui": "1.8.16", + "@reown/appkit-utils": "1.8.16", + "@reown/appkit-wallet": "1.8.16", "lit": "3.3.0" } }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit-ui": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.8.15.tgz", - "integrity": "sha512-TDyv3Sn1LMumfbibPjoA8fYs2jeIrgSLQf9aVk6Nc5jc3gYFWW7wrtU5l1SLSlDJR/w8/13GUQuVQNfaGSfj4A==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.8.16.tgz", + "integrity": "sha512-yd9BtyRUk6zAVQcc8W2t5qqXVHJUweiZ7y/tIeuaGDuG8zRWlWQTX6Q2ivBeLI2fZNix7Or90IpnlcdaOCo2Lw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@phosphor-icons/webcomponents": "2.1.5", - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-wallet": "1.8.15", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-wallet": "1.8.16", "lit": "3.3.0", "qrcode": "1.5.3" } }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit-utils": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.8.15.tgz", - "integrity": "sha512-T5MEg7aZ4rOFsKfIQKe83dRPalLtQr6AlsWokZmJpN/bq/sOB8kUvNlOju7drsMAcoWRYSVnXFMYNBqNVymMBg==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.8.16.tgz", + "integrity": "sha512-tCi2ZEOoOIGiddRAy9lJ1jnYj0zMnqEojIk095sWvnMdlNfn/lZdsLt62AGqk5khnlsyg2Zo0vszPBcXLH8/ww==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-polyfills": "1.8.15", - "@reown/appkit-wallet": "1.8.15", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-polyfills": "1.8.16", + "@reown/appkit-wallet": "1.8.16", "@wallet-standard/wallet": "1.1.0", - "@walletconnect/logger": "3.0.0", - "@walletconnect/universal-provider": "2.23.0", + "@walletconnect/logger": "3.0.1", + "@walletconnect/universal-provider": "2.23.1", "valtio": "2.1.7", "viem": ">=2.37.9" }, @@ -9525,14 +9581,14 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@reown/appkit-wallet": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.15.tgz", - "integrity": "sha512-Ui6bfYU6ENDzR1dmKq3Oj+FhxKiFmLHFGTT915BWJrqOSqET4Kku4OIRLIqshzm8ohdsPTdyazZbaTRErYi3iA==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.16.tgz", + "integrity": "sha512-UARNgRtzTVojDv2wgILy7RKiYAXpFX9UE7qkficV4oB+IQX7yCPpa0eXN2mDXZBVSz2hSu4rLTa7WNXzZPal/A==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-polyfills": "1.8.15", - "@walletconnect/logger": "3.0.0", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-polyfills": "1.8.16", + "@walletconnect/logger": "3.0.1", "zod": "3.22.4" } }, @@ -9571,16 +9627,10 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, - "node_modules/@privy-io/react-auth/node_modules/@types/stylis": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", - "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", - "license": "MIT" - }, "node_modules/@privy-io/react-auth/node_modules/@walletconnect/core": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.0.tgz", - "integrity": "sha512-W++xuXf+AsMPrBWn1It8GheIbCTp1ynTQP+aoFB86eUwyCtSiK7UQsn/+vJZdwElrn+Ptp2A0RqQx2onTMVHjQ==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.1.tgz", + "integrity": "sha512-fW48PIw41Q/LJW+q0msFogD/OcelkrrDONQMcpGw4C4Y6w+IvFKGEg+7dxGLKWx1g8QuHk/p6C9VEIV/tDsm5A==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/heartbeat": "1.2.2", @@ -9589,13 +9639,13 @@ "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.39.3", "events": "3.3.0", @@ -9721,9 +9771,9 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@walletconnect/logger": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", - "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.1.tgz", + "integrity": "sha512-O8lXGMZO1+e5NtHhBSjsAih/I9KC+1BxNhGNGD+SIWTqWd0zsbT5wJtNnJ+LnSXTRE7XZRxFUlvZgkER3vlhFA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.2", @@ -9771,33 +9821,33 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@walletconnect/sign-client": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.0.tgz", - "integrity": "sha512-Nzf5x/LnQgC0Yjk0NmkT8kdrIMcScpALiFm9gP0n3CulL+dkf3HumqWzdoTmQSqGPxwHu/TNhGOaRKZLGQXSqw==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.1.tgz", + "integrity": "sha512-x0sG8ZuuaOi3G/gYWLppf7nmNItWlV8Yga9Bltb46/Ve6G20nCBis6gcTVVeJOpnmqQ85FISwExqOYPmJ0FQlw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@walletconnect/core": "2.23.0", + "@walletconnect/core": "2.23.1", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "events": "3.3.0" } }, "node_modules/@privy-io/react-auth/node_modules/@walletconnect/types": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", - "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.1.tgz", + "integrity": "sha512-sbWOM9oCuzSbz/187rKWnSB3sy7FCFcbTQYeIJMc9+HTMTG2TUPftPCn8NnkfvmXbIeyLw00Y0KNvXoCV/eIeQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "events": "3.3.0" } }, @@ -9917,9 +9967,9 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@walletconnect/universal-provider": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.0.tgz", - "integrity": "sha512-3ZEqAsbtCbk+CV0ZLpy7Qzc04KXEnrW4zCboZ+gkkC0ey4H62x9h23kBOIrU9qew6orjA7D5gg0ikRC2Up1lbw==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.1.tgz", + "integrity": "sha512-XlvG1clsL7Ds+g28Oz5dXsPA+5ERtQGYvd+L8cskMaTvtphGhipVGgX8WNAhp7p1gfNcDg4tCiTHlj131jctwA==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/events": "1.0.1", @@ -9928,10 +9978,10 @@ "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", - "@walletconnect/sign-client": "2.23.0", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/logger": "3.0.1", + "@walletconnect/sign-client": "2.23.1", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "es-toolkit": "1.39.3", "events": "3.3.0" } @@ -10052,9 +10102,9 @@ } }, "node_modules/@privy-io/react-auth/node_modules/@walletconnect/utils": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.0.tgz", - "integrity": "sha512-bVyv4Hl+/wVGueZ6rEO0eYgDy5deSBA4JjpJHAMOdaNoYs05NTE1HymV2lfPQQHuqc7suYexo9jwuW7i3JLuAA==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.1.tgz", + "integrity": "sha512-J12DadZHIL0KvsUoQuK0rag9jDUy8qu1zwz47xEHl03LrMcgrotQiXvdTQ3uHwAVA4yKLTQB/LEI2JiTIt7X8Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@msgpack/msgpack": "3.1.2", @@ -10064,12 +10114,12 @@ "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", + "@walletconnect/types": "2.23.1", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", @@ -10266,12 +10316,6 @@ "node": ">=6" } }, - "node_modules/@privy-io/react-auth/node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, "node_modules/@privy-io/react-auth/node_modules/dayjs": { "version": "1.11.13", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", @@ -10534,19 +10578,19 @@ } }, "node_modules/@privy-io/react-auth/node_modules/styled-components": { - "version": "6.1.19", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", - "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.2.0.tgz", + "integrity": "sha512-ryFCkETE++8jlrBmC+BoGPUN96ld1/Yp0s7t5bcXDobrs4XoXroY1tN+JbFi09hV6a5h3MzbcVi8/BGDP0eCgQ==", "license": "MIT", "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", - "@types/stylis": "4.2.5", + "@types/stylis": "4.2.7", "css-to-react-native": "3.2.0", - "csstype": "3.1.3", + "csstype": "3.2.3", "postcss": "8.4.49", "shallowequal": "1.1.0", - "stylis": "4.3.2", + "stylis": "4.3.6", "tslib": "2.6.2" }, "engines": { @@ -10561,12 +10605,6 @@ "react-dom": ">= 16.8.0" } }, - "node_modules/@privy-io/react-auth/node_modules/styled-components/node_modules/stylis": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", - "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", - "license": "MIT" - }, "node_modules/@privy-io/react-auth/node_modules/stylis": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", @@ -13023,22 +13061,22 @@ } }, "node_modules/@reown/appkit-controllers": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.8.15.tgz", - "integrity": "sha512-aCzA8yGQbicLRjU62is+viuVFl2dvpZVnLPG0/2eQbFkCZsawCldbFPfviiTuDsBx7o1pG90Q5rC6LgYoVWA0w==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.8.16.tgz", + "integrity": "sha512-GzhC+/AAYoyLYs/jJd7/D/tv7WCoB4wfv6VkpYcS+3NjL1orGqYnPIXiieiDEGwbfM8h08lmlCsEwOrEoIrchA==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-wallet": "1.8.15", - "@walletconnect/universal-provider": "2.23.0", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-wallet": "1.8.16", + "@walletconnect/universal-provider": "2.23.1", "valtio": "2.1.7", "viem": ">=2.37.9" } }, "node_modules/@reown/appkit-controllers/node_modules/@reown/appkit-common": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.15.tgz", - "integrity": "sha512-swDeGli08KQWB2nkFB5a61IEAfaM5AeDwp5inzlsfW1lHOwS5uO052nacr6wQCCKEp9aWojdEScwnk3qiVFNjQ==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.16.tgz", + "integrity": "sha512-og7EkTEI+mxTEEK3cRoX2PJqgij/5t9CJeN/2dnOef8mEiNh0vAPmdzZPXw9v4oVeBsu14jb8n/Y7vIbTOwl6Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "big.js": "6.2.2", @@ -13047,30 +13085,30 @@ } }, "node_modules/@reown/appkit-controllers/node_modules/@reown/appkit-polyfills": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.15.tgz", - "integrity": "sha512-IDq57jf/a//meerJ7Zl7TG9jxpiQ3dJexv68SlzWWUow0DtDd0TMgykofUq5gzBLZBoFexbHyPZih/ylhScVPg==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.16.tgz", + "integrity": "sha512-6ArFDoIbI/DHHCdOCSnh7THP4OvhG5XKKgXbCKSNOuj3/RPl3OmmoFJwwf+LvZJ4ggaz7I6qoXFHf8fEEx1FcQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "buffer": "6.0.3" } }, "node_modules/@reown/appkit-controllers/node_modules/@reown/appkit-wallet": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.15.tgz", - "integrity": "sha512-Ui6bfYU6ENDzR1dmKq3Oj+FhxKiFmLHFGTT915BWJrqOSqET4Kku4OIRLIqshzm8ohdsPTdyazZbaTRErYi3iA==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.16.tgz", + "integrity": "sha512-UARNgRtzTVojDv2wgILy7RKiYAXpFX9UE7qkficV4oB+IQX7yCPpa0eXN2mDXZBVSz2hSu4rLTa7WNXzZPal/A==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-polyfills": "1.8.15", - "@walletconnect/logger": "3.0.0", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-polyfills": "1.8.16", + "@walletconnect/logger": "3.0.1", "zod": "3.22.4" } }, "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/core": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.0.tgz", - "integrity": "sha512-W++xuXf+AsMPrBWn1It8GheIbCTp1ynTQP+aoFB86eUwyCtSiK7UQsn/+vJZdwElrn+Ptp2A0RqQx2onTMVHjQ==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.1.tgz", + "integrity": "sha512-fW48PIw41Q/LJW+q0msFogD/OcelkrrDONQMcpGw4C4Y6w+IvFKGEg+7dxGLKWx1g8QuHk/p6C9VEIV/tDsm5A==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/heartbeat": "1.2.2", @@ -13079,13 +13117,13 @@ "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.39.3", "events": "3.3.0", @@ -13115,9 +13153,9 @@ } }, "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/logger": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", - "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.1.tgz", + "integrity": "sha512-O8lXGMZO1+e5NtHhBSjsAih/I9KC+1BxNhGNGD+SIWTqWd0zsbT5wJtNnJ+LnSXTRE7XZRxFUlvZgkER3vlhFA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.2", @@ -13165,40 +13203,40 @@ } }, "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/sign-client": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.0.tgz", - "integrity": "sha512-Nzf5x/LnQgC0Yjk0NmkT8kdrIMcScpALiFm9gP0n3CulL+dkf3HumqWzdoTmQSqGPxwHu/TNhGOaRKZLGQXSqw==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.1.tgz", + "integrity": "sha512-x0sG8ZuuaOi3G/gYWLppf7nmNItWlV8Yga9Bltb46/Ve6G20nCBis6gcTVVeJOpnmqQ85FISwExqOYPmJ0FQlw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@walletconnect/core": "2.23.0", + "@walletconnect/core": "2.23.1", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "events": "3.3.0" } }, "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/types": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", - "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.1.tgz", + "integrity": "sha512-sbWOM9oCuzSbz/187rKWnSB3sy7FCFcbTQYeIJMc9+HTMTG2TUPftPCn8NnkfvmXbIeyLw00Y0KNvXoCV/eIeQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "events": "3.3.0" } }, "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/universal-provider": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.0.tgz", - "integrity": "sha512-3ZEqAsbtCbk+CV0ZLpy7Qzc04KXEnrW4zCboZ+gkkC0ey4H62x9h23kBOIrU9qew6orjA7D5gg0ikRC2Up1lbw==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.1.tgz", + "integrity": "sha512-XlvG1clsL7Ds+g28Oz5dXsPA+5ERtQGYvd+L8cskMaTvtphGhipVGgX8WNAhp7p1gfNcDg4tCiTHlj131jctwA==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/events": "1.0.1", @@ -13207,18 +13245,18 @@ "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", - "@walletconnect/sign-client": "2.23.0", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/logger": "3.0.1", + "@walletconnect/sign-client": "2.23.1", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "es-toolkit": "1.39.3", "events": "3.3.0" } }, "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/utils": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.0.tgz", - "integrity": "sha512-bVyv4Hl+/wVGueZ6rEO0eYgDy5deSBA4JjpJHAMOdaNoYs05NTE1HymV2lfPQQHuqc7suYexo9jwuW7i3JLuAA==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.1.tgz", + "integrity": "sha512-J12DadZHIL0KvsUoQuK0rag9jDUy8qu1zwz47xEHl03LrMcgrotQiXvdTQ3uHwAVA4yKLTQB/LEI2JiTIt7X8Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@msgpack/msgpack": "3.1.2", @@ -13228,12 +13266,12 @@ "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", + "@walletconnect/types": "2.23.1", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", @@ -13909,23 +13947,23 @@ } }, "node_modules/@reown/appkit-pay": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-pay/-/appkit-pay-1.8.15.tgz", - "integrity": "sha512-4byUi+/TBLFbwvgtBjT01zyLo5sAmn8bcOvOp+NpI0UMTWgl2oNbRLVSzPGak3YXBLxiDCdxhnbbA0wqWFPM0A==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-pay/-/appkit-pay-1.8.16.tgz", + "integrity": "sha512-V5M9SZnV00ogMeuQDwd0xY6Fa4+yU9NhmWISt0iiAGpNNtKdF+NWybWFbi2GkGjg4IvlJJBBgBlIZtmlZRq8SQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-ui": "1.8.15", - "@reown/appkit-utils": "1.8.15", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-ui": "1.8.16", + "@reown/appkit-utils": "1.8.16", "lit": "3.3.0", "valtio": "2.1.7" } }, "node_modules/@reown/appkit-pay/node_modules/@reown/appkit-common": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.15.tgz", - "integrity": "sha512-swDeGli08KQWB2nkFB5a61IEAfaM5AeDwp5inzlsfW1lHOwS5uO052nacr6wQCCKEp9aWojdEScwnk3qiVFNjQ==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.16.tgz", + "integrity": "sha512-og7EkTEI+mxTEEK3cRoX2PJqgij/5t9CJeN/2dnOef8mEiNh0vAPmdzZPXw9v4oVeBsu14jb8n/Y7vIbTOwl6Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "big.js": "6.2.2", @@ -13934,41 +13972,41 @@ } }, "node_modules/@reown/appkit-pay/node_modules/@reown/appkit-polyfills": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.15.tgz", - "integrity": "sha512-IDq57jf/a//meerJ7Zl7TG9jxpiQ3dJexv68SlzWWUow0DtDd0TMgykofUq5gzBLZBoFexbHyPZih/ylhScVPg==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.16.tgz", + "integrity": "sha512-6ArFDoIbI/DHHCdOCSnh7THP4OvhG5XKKgXbCKSNOuj3/RPl3OmmoFJwwf+LvZJ4ggaz7I6qoXFHf8fEEx1FcQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "buffer": "6.0.3" } }, "node_modules/@reown/appkit-pay/node_modules/@reown/appkit-ui": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.8.15.tgz", - "integrity": "sha512-TDyv3Sn1LMumfbibPjoA8fYs2jeIrgSLQf9aVk6Nc5jc3gYFWW7wrtU5l1SLSlDJR/w8/13GUQuVQNfaGSfj4A==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.8.16.tgz", + "integrity": "sha512-yd9BtyRUk6zAVQcc8W2t5qqXVHJUweiZ7y/tIeuaGDuG8zRWlWQTX6Q2ivBeLI2fZNix7Or90IpnlcdaOCo2Lw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@phosphor-icons/webcomponents": "2.1.5", - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-wallet": "1.8.15", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-wallet": "1.8.16", "lit": "3.3.0", "qrcode": "1.5.3" } }, "node_modules/@reown/appkit-pay/node_modules/@reown/appkit-utils": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.8.15.tgz", - "integrity": "sha512-T5MEg7aZ4rOFsKfIQKe83dRPalLtQr6AlsWokZmJpN/bq/sOB8kUvNlOju7drsMAcoWRYSVnXFMYNBqNVymMBg==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.8.16.tgz", + "integrity": "sha512-tCi2ZEOoOIGiddRAy9lJ1jnYj0zMnqEojIk095sWvnMdlNfn/lZdsLt62AGqk5khnlsyg2Zo0vszPBcXLH8/ww==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-controllers": "1.8.15", - "@reown/appkit-polyfills": "1.8.15", - "@reown/appkit-wallet": "1.8.15", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-controllers": "1.8.16", + "@reown/appkit-polyfills": "1.8.16", + "@reown/appkit-wallet": "1.8.16", "@wallet-standard/wallet": "1.1.0", - "@walletconnect/logger": "3.0.0", - "@walletconnect/universal-provider": "2.23.0", + "@walletconnect/logger": "3.0.1", + "@walletconnect/universal-provider": "2.23.1", "valtio": "2.1.7", "viem": ">=2.37.9" }, @@ -13982,14 +14020,14 @@ } }, "node_modules/@reown/appkit-pay/node_modules/@reown/appkit-wallet": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.15.tgz", - "integrity": "sha512-Ui6bfYU6ENDzR1dmKq3Oj+FhxKiFmLHFGTT915BWJrqOSqET4Kku4OIRLIqshzm8ohdsPTdyazZbaTRErYi3iA==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.16.tgz", + "integrity": "sha512-UARNgRtzTVojDv2wgILy7RKiYAXpFX9UE7qkficV4oB+IQX7yCPpa0eXN2mDXZBVSz2hSu4rLTa7WNXzZPal/A==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@reown/appkit-common": "1.8.15", - "@reown/appkit-polyfills": "1.8.15", - "@walletconnect/logger": "3.0.0", + "@reown/appkit-common": "1.8.16", + "@reown/appkit-polyfills": "1.8.16", + "@walletconnect/logger": "3.0.1", "zod": "3.22.4" } }, @@ -14005,9 +14043,9 @@ } }, "node_modules/@reown/appkit-pay/node_modules/@walletconnect/core": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.0.tgz", - "integrity": "sha512-W++xuXf+AsMPrBWn1It8GheIbCTp1ynTQP+aoFB86eUwyCtSiK7UQsn/+vJZdwElrn+Ptp2A0RqQx2onTMVHjQ==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.1.tgz", + "integrity": "sha512-fW48PIw41Q/LJW+q0msFogD/OcelkrrDONQMcpGw4C4Y6w+IvFKGEg+7dxGLKWx1g8QuHk/p6C9VEIV/tDsm5A==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/heartbeat": "1.2.2", @@ -14016,13 +14054,13 @@ "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.39.3", "events": "3.3.0", @@ -14052,9 +14090,9 @@ } }, "node_modules/@reown/appkit-pay/node_modules/@walletconnect/logger": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", - "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.1.tgz", + "integrity": "sha512-O8lXGMZO1+e5NtHhBSjsAih/I9KC+1BxNhGNGD+SIWTqWd0zsbT5wJtNnJ+LnSXTRE7XZRxFUlvZgkER3vlhFA==", "license": "MIT", "dependencies": { "@walletconnect/safe-json": "^1.0.2", @@ -14102,40 +14140,40 @@ } }, "node_modules/@reown/appkit-pay/node_modules/@walletconnect/sign-client": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.0.tgz", - "integrity": "sha512-Nzf5x/LnQgC0Yjk0NmkT8kdrIMcScpALiFm9gP0n3CulL+dkf3HumqWzdoTmQSqGPxwHu/TNhGOaRKZLGQXSqw==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.1.tgz", + "integrity": "sha512-x0sG8ZuuaOi3G/gYWLppf7nmNItWlV8Yga9Bltb46/Ve6G20nCBis6gcTVVeJOpnmqQ85FISwExqOYPmJ0FQlw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@walletconnect/core": "2.23.0", + "@walletconnect/core": "2.23.1", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "events": "3.3.0" } }, "node_modules/@reown/appkit-pay/node_modules/@walletconnect/types": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", - "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.1.tgz", + "integrity": "sha512-sbWOM9oCuzSbz/187rKWnSB3sy7FCFcbTQYeIJMc9+HTMTG2TUPftPCn8NnkfvmXbIeyLw00Y0KNvXoCV/eIeQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "events": "3.3.0" } }, "node_modules/@reown/appkit-pay/node_modules/@walletconnect/universal-provider": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.0.tgz", - "integrity": "sha512-3ZEqAsbtCbk+CV0ZLpy7Qzc04KXEnrW4zCboZ+gkkC0ey4H62x9h23kBOIrU9qew6orjA7D5gg0ikRC2Up1lbw==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.1.tgz", + "integrity": "sha512-XlvG1clsL7Ds+g28Oz5dXsPA+5ERtQGYvd+L8cskMaTvtphGhipVGgX8WNAhp7p1gfNcDg4tCiTHlj131jctwA==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@walletconnect/events": "1.0.1", @@ -14144,18 +14182,18 @@ "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", - "@walletconnect/sign-client": "2.23.0", - "@walletconnect/types": "2.23.0", - "@walletconnect/utils": "2.23.0", + "@walletconnect/logger": "3.0.1", + "@walletconnect/sign-client": "2.23.1", + "@walletconnect/types": "2.23.1", + "@walletconnect/utils": "2.23.1", "es-toolkit": "1.39.3", "events": "3.3.0" } }, "node_modules/@reown/appkit-pay/node_modules/@walletconnect/utils": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.0.tgz", - "integrity": "sha512-bVyv4Hl+/wVGueZ6rEO0eYgDy5deSBA4JjpJHAMOdaNoYs05NTE1HymV2lfPQQHuqc7suYexo9jwuW7i3JLuAA==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.1.tgz", + "integrity": "sha512-J12DadZHIL0KvsUoQuK0rag9jDUy8qu1zwz47xEHl03LrMcgrotQiXvdTQ3uHwAVA4yKLTQB/LEI2JiTIt7X8Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@msgpack/msgpack": "3.1.2", @@ -14165,12 +14203,12 @@ "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "3.0.0", + "@walletconnect/logger": "3.0.1", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.23.0", + "@walletconnect/types": "2.23.1", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", @@ -18486,9 +18524,9 @@ } }, "node_modules/@solana/rpc-transport-http/node_modules/undici-types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.17.0.tgz", - "integrity": "sha512-aCt4oiOwwDSB1SBIKNLuUghX8LHAZvY6qMaM0e8mifQpxbfqIUvCTF3W0M0wqM0s51opMMfni9999DzdWbaSLw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT", "optional": true }, @@ -19321,6 +19359,12 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -19649,12 +19693,12 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.13.16", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.16.tgz", - "integrity": "sha512-y4xLKvLu6UZWiGdNcgk3yYlzCznYIV0m8dSyUzr3eAC0dHLos5V74qhUHxutYddFGgGU8sWLkp6H5c2RCrsrXw==", + "version": "3.13.17", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.17.tgz", + "integrity": "sha512-gtjQr4CIb86rq03AL4WJnlTaaTU5UU4Xt8tbG1HU3OWVsO4z5OrRKTRDKoWRbkLEPpbPIjPgCoxmV70jTJtWZQ==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.13.16" + "@tanstack/virtual-core": "3.13.17" }, "funding": { "type": "github", @@ -19666,9 +19710,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.13.16", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.16.tgz", - "integrity": "sha512-njazUC8mDkrxWmyZmn/3eXrDcP8Msb3chSr4q6a65RmwdSbMlMCdnOphv6/8mLO7O3Fuza5s4M4DclmvAO5w0w==", + "version": "3.13.17", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.17.tgz", + "integrity": "sha512-m5mRfGNcL5GUzluWNom0Rmg8P8Dg3h6PnJtJBmJcBiJvkV+vufmUfLnVzKSPGQtmvzMW/ZuUdvL+SyjIUvHV3A==", "license": "MIT", "funding": { "type": "github", @@ -20603,9 +20647,9 @@ "license": "MIT" }, "node_modules/@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -24413,9 +24457,9 @@ "license": "MIT" }, "node_modules/axe-core": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", - "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", + "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", "dev": true, "license": "MPL-2.0", "engines": { @@ -24812,9 +24856,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "version": "2.9.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.12.tgz", + "integrity": "sha512-Mij6Lij93pTAIsSYy5cyBQ975Qh9uLEc5rwGTpomiZeXZL9yIS6uORJakb3ScHgfs0serMMfIbXzokPMuEiRyw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -25011,6 +25055,20 @@ "node": ">=18.0.0" } }, + "node_modules/bitcoinjs-lib/node_modules/valibot": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.38.0.tgz", + "integrity": "sha512-RCJa0fetnzp+h+KN9BdgYOgtsMAG9bfoJ9JSjIhFHobKWVWyzM3jjaeNTdpFK9tQtf3q1sguXeERJ/LcmdFE7w==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/blake3-wasm": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", @@ -25177,6 +25235,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -30937,6 +30996,12 @@ "node": "> 0.1.90" } }, + "node_modules/fancy-canvas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fancy-canvas/-/fancy-canvas-2.1.0.tgz", + "integrity": "sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ==", + "license": "MIT" + }, "node_modules/fast-copy": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", @@ -31760,13 +31825,13 @@ } }, "node_modules/framer-motion": { - "version": "12.23.28", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.28.tgz", - "integrity": "sha512-AXLnVEC/HHWp6Va1l9xl6cIM4SgdZAmgPLGy/h9w07NOxg0njva/A+3uBE3QUQ3uooi8c8c8HPn/8Md9ol0glg==", + "version": "12.24.10", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.24.10.tgz", + "integrity": "sha512-8yoyMkCn2RmV9UB9mfmMuzKyenQe909hRQRl0yGBhbZJjZZ9bSU87NIGAruqCXCuTNCA0qHw2LWLrcXLL9GF6A==", "license": "MIT", "dependencies": { - "motion-dom": "^12.23.28", - "motion-utils": "^12.23.28", + "motion-dom": "^12.24.10", + "motion-utils": "^12.24.10", "tslib": "^2.4.0" }, "peerDependencies": { @@ -33049,7 +33114,9 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" + "dev": true, + "license": "ISC", + "peer": true }, "node_modules/input-otp": { "version": "1.4.2", @@ -33992,6 +34059,15 @@ "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", "license": "MIT" }, + "node_modules/jayson/node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/jayson/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -36327,6 +36403,15 @@ "integrity": "sha512-r9kw4OA6oDO4dPXkOrXTkArQAafIKAU71hChInV4FxZ69dxCfbwQGDPzqR5/vea94wU705/3AZroEbSoeVWrQw==", "license": "MIT" }, + "node_modules/lightweight-charts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/lightweight-charts/-/lightweight-charts-5.1.0.tgz", + "integrity": "sha512-jEAYR4ODYeyNZcWUigsoLTl52rbPmgXnvd5FLIv/ZoA/2sSDw63YKnef8n4yhzum7W926yHeFwlm7ididKb7YQ==", + "license": "Apache-2.0", + "dependencies": { + "fancy-canvas": "2.1.0" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -36777,12 +36862,77 @@ "node": ">= 0.6" } }, + "node_modules/micro-eth-signer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.18.1.tgz", + "integrity": "sha512-vXKhCZxrytpl+dXR9JeaE41ZVFndi7wCKc1Jd22smOMAeDErvRcXaTxhYUf1yQxis4n2kIdv/pH7iuf+5/cj+Q==", + "license": "MIT", + "dependencies": { + "@noble/curves": "^2.0.0", + "@noble/hashes": "^2.0.0", + "micro-packed": "^0.8.0" + }, + "engines": { + "node": ">= 20.19.0" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", + "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.0.1" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/micro-ftch": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", "license": "MIT" }, + "node_modules/micro-packed": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.8.0.tgz", + "integrity": "sha512-AKb8znIvg9sooythbXzyFeChEY0SkW0C6iXECpy/ls0e5BtwXO45J9wD9SLzBztnS4XmF/5kwZknsq+jyynd/A==", + "license": "MIT", + "dependencies": { + "@scure/base": "2.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed/node_modules/@scure/base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz", + "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -36965,9 +37115,9 @@ } }, "node_modules/miniflare": { - "version": "4.20251210.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20251210.0.tgz", - "integrity": "sha512-k6kIoXwGVqlPZb0hcn+X7BmnK+8BjIIkusQPY22kCo2RaQJ/LzAjtxHQdGXerlHSnJyQivDQsL6BJHMpQfUFyw==", + "version": "4.20260103.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260103.0.tgz", + "integrity": "sha512-iuSU0e+KMuFD7gxuPKoJXFi6cvDu/w/lQP4Wayq3v+YsmZ0dVMAJY9LMZ0TKMLicdAj2So9WcReAhJmJJ9Ppnw==", "dev": true, "license": "MIT", "dependencies": { @@ -36979,10 +37129,10 @@ "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", - "workerd": "1.20251210.0", + "workerd": "1.20260103.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", - "zod": "3.22.3" + "zod": "^3.25.76" }, "bin": { "miniflare": "bootstrap.js" @@ -37037,16 +37187,6 @@ "node": ">=20.18.1" } }, - "node_modules/miniflare/node_modules/zod": { - "version": "3.22.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", - "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -37063,6 +37203,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -37087,6 +37228,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -37162,18 +37304,18 @@ } }, "node_modules/motion-dom": { - "version": "12.23.28", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.28.tgz", - "integrity": "sha512-XxQ0QDS7nXjug1Q4Z7hwD1DPDM+zJvgteSlQABse1N4F22q6wRLLjBEeMelvJrZNPp9UeS4Q3AVpWzWBLHLmew==", + "version": "12.24.10", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.24.10.tgz", + "integrity": "sha512-H3HStYaJ6wANoZVNT0ZmYZHGvrpvi9pKJRzsgNEHkdITR4Qd9FFu2e9sH4e2Phr4tKCmyyloex6SOSmv0Tlq+g==", "license": "MIT", "dependencies": { - "motion-utils": "^12.23.28" + "motion-utils": "^12.24.10" } }, "node_modules/motion-utils": { - "version": "12.23.28", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.28.tgz", - "integrity": "sha512-0W6cWd5Okoyf8jmessVK3spOmbyE0yTdNKujHctHH9XdAE4QDuZ1/LjSXC68rrhsJU+TkzXURC5OdSWh9ibOwQ==", + "version": "12.24.10", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.24.10.tgz", + "integrity": "sha512-x5TFgkCIP4pPsRLpKoI86jv/q8t8FQOiM/0E8QKBzfMozWHfkKap2gA1hOki+B5g3IsBNpxbUnfOum1+dgvYww==", "license": "MIT" }, "node_modules/ms": { @@ -37267,6 +37409,16 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -42802,9 +42954,9 @@ "license": "MIT" }, "node_modules/preact": { - "version": "10.28.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.1.tgz", - "integrity": "sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==", + "version": "10.28.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", + "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", "license": "MIT", "funding": { "type": "opencollective", @@ -43104,209 +43256,6 @@ "teleport": ">=0.2.0" } }, - "node_modules/qrcode": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "dijkstrajs": "^1.0.1", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/qrcode/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/qrcode/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qrcode/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/qrcode/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "extraneous": true, - "license": "MIT" - }, - "node_modules/qrcode/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/qrcode/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "extraneous": true, - "license": "ISC" - }, - "node_modules/qrcode/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "extraneous": true, - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "extraneous": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/qs": { "version": "6.12.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", @@ -43866,18 +43815,6 @@ "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", "license": "MIT" }, - "node_modules/react-loader-spinner/node_modules/@types/stylis": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", - "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", - "license": "MIT" - }, - "node_modules/react-loader-spinner/node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, "node_modules/react-loader-spinner/node_modules/postcss": { "version": "8.4.49", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", @@ -43907,19 +43844,19 @@ } }, "node_modules/react-loader-spinner/node_modules/styled-components": { - "version": "6.1.19", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", - "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.2.0.tgz", + "integrity": "sha512-ryFCkETE++8jlrBmC+BoGPUN96ld1/Yp0s7t5bcXDobrs4XoXroY1tN+JbFi09hV6a5h3MzbcVi8/BGDP0eCgQ==", "license": "MIT", "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", - "@types/stylis": "4.2.5", + "@types/stylis": "4.2.7", "css-to-react-native": "3.2.0", - "csstype": "3.1.3", + "csstype": "3.2.3", "postcss": "8.4.49", "shallowequal": "1.1.0", - "stylis": "4.3.2", + "stylis": "4.3.6", "tslib": "2.6.2" }, "engines": { @@ -43935,9 +43872,9 @@ } }, "node_modules/react-loader-spinner/node_modules/stylis": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", - "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", "license": "MIT" }, "node_modules/react-redux": { @@ -45255,15 +45192,6 @@ "utf-8-validate": "^5.0.2" } }, - "node_modules/rpc-websockets/node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/rpc-websockets/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -46027,7 +45955,9 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" + "dev": true, + "license": "ISC", + "peer": true }, "node_modules/simple-swizzle": { "version": "0.2.4", @@ -48390,7 +48320,9 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "is-typedarray": "^1.0.0" } @@ -48528,9 +48460,9 @@ } }, "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.2.tgz", + "integrity": "sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==", "license": "MIT" }, "node_modules/uglify-js": { @@ -48982,9 +48914,9 @@ } }, "node_modules/valibot": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.38.0.tgz", - "integrity": "sha512-RCJa0fetnzp+h+KN9BdgYOgtsMAG9bfoJ9JSjIhFHobKWVWyzM3jjaeNTdpFK9tQtf3q1sguXeERJ/LcmdFE7w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", + "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", "license": "MIT", "peerDependencies": { "typescript": ">=5" @@ -50514,17 +50446,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/webpack-dev-server/node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -51578,9 +51499,9 @@ } }, "node_modules/workerd": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20251210.0.tgz", - "integrity": "sha512-9MUUneP1BnRE9XAYi94FXxHmiLGbO75EHQZsgWqSiOXjoXSqJCw8aQbIEPxCy19TclEl/kHUFYce8ST2W+Qpjw==", + "version": "1.20260103.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260103.0.tgz", + "integrity": "sha512-uB5eliFHVCdPD3uaPGe6zNRFjWzijOb26c0/1oXKmQFUSUR7GFPCTTd0iJXZAGKZDZ0DNgzQCPoolWelz6W5Zg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -51591,28 +51512,28 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20251210.0", - "@cloudflare/workerd-darwin-arm64": "1.20251210.0", - "@cloudflare/workerd-linux-64": "1.20251210.0", - "@cloudflare/workerd-linux-arm64": "1.20251210.0", - "@cloudflare/workerd-windows-64": "1.20251210.0" + "@cloudflare/workerd-darwin-64": "1.20260103.0", + "@cloudflare/workerd-darwin-arm64": "1.20260103.0", + "@cloudflare/workerd-linux-64": "1.20260103.0", + "@cloudflare/workerd-linux-arm64": "1.20260103.0", + "@cloudflare/workerd-windows-64": "1.20260103.0" } }, "node_modules/wrangler": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.54.0.tgz", - "integrity": "sha512-bANFsjDwJLbprYoBK+hUDZsVbUv2SqJd8QvArLIcZk+fPq4h/Ohtj5vkKXD3k0s2bD1DXLk08D+hYmeNH+xC6A==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.57.0.tgz", + "integrity": "sha512-JTVHmL2zr5PUJ22kT21fNXZBgVm4WzXSHsVc+VVIRANBVgTwn6EikXBx1DMyvHDQP6vkaojuyrRjeasB7rxV9A==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { "@cloudflare/kv-asset-handler": "0.4.1", - "@cloudflare/unenv-preset": "2.7.13", + "@cloudflare/unenv-preset": "2.8.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.0", - "miniflare": "4.20251210.0", + "miniflare": "4.20260103.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20251210.0" + "workerd": "1.20260103.0" }, "bin": { "wrangler": "bin/wrangler.js", @@ -51625,7 +51546,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20251210.0" + "@cloudflare/workers-types": "^4.20260103.0" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -52262,7 +52183,9 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, "license": "ISC", + "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", diff --git a/package.json b/package.json index b022c866..38473dde 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,17 @@ "name": "pillarx", "version": "1.0.0", "private": true, + "type": "module", "scripts": { "dev": "vite", "dev:functions": "wrangler pages dev build --port 5173 --live-reload", - "build": "VITE_COMMIT_SHA=$CF_PAGES_COMMIT_SHA VITE_VERSION=$npm_package_version vite build", + "build": "NODE_OPTIONS='--max-old-space-size=8192' VITE_COMMIT_SHA=$CF_PAGES_COMMIT_SHA VITE_VERSION=$npm_package_version vite build", "preview": "vite preview", "test": "vitest", "test:watch": "eslint . && vitest", "test:update": "vitest -u", "test:ci": "vitest run --coverage", "sentry:sourcemaps": "sentry-cli sourcemaps inject --org pillar-project --project x ./build && sentry-cli sourcemaps upload --org pillar-project --project x ./build", - "postinstall": "patch-package", "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", "lint:fix": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix", "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" @@ -24,11 +24,13 @@ "@etherspot/intent-sdk": "1.0.0-alpha.12", "@etherspot/modular-sdk": "6.1.1", "@etherspot/transaction-kit": "2.1.4", + "@hookform/resolvers": "^5.2.2", "@hypelab/sdk-react": "1.0.4", "@lifi/sdk": "3.6.8", "@mui/icons-material": "5.16.6", "@mui/joy": "5.0.0-beta.48", "@mui/material": "5.16.6", + "@nktkas/hyperliquid": "^0.30.2", "@privy-io/react-auth": "2.16.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", @@ -89,11 +91,13 @@ "iconsax-react": "0.0.8", "identicon.js": "2.3.3", "input-otp": "^1.4.2", + "lightweight-charts": "^5.1.0", "lodash": "4.17.21", "lucide-react": "^0.462.0", "luxon": "3.5.0", "mime": "4.0.4", "moment": "2.30.1", + "next-themes": "^0.4.6", "patch-package": "8.0.0", "plausible-tracker": "0.3.9", "prop-types": "15.8.1", @@ -128,7 +132,8 @@ "viem": "2.37.1", "vite-plugin-svgr": "4.3.0", "wagmi": "2.14.16", - "webfontloader": "1.6.28" + "webfontloader": "1.6.28", + "zod": "^3.25.76" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11", @@ -212,4 +217,4 @@ "resolutions": { "styled-components": "6.1.1" } -} +} \ No newline at end of file diff --git a/postcss.config.js b/postcss.config.js index 9f239969..2aa7205d 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,4 @@ -// eslint-disable-next-line no-undef -module.exports = { +export default { plugins: { tailwindcss: {}, autoprefixer: {}, diff --git a/src/apps/perps/App.css b/src/apps/perps/App.css new file mode 100644 index 00000000..b9d355df --- /dev/null +++ b/src/apps/perps/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/src/apps/perps/components/AgentControls.tsx b/src/apps/perps/components/AgentControls.tsx new file mode 100644 index 00000000..74627992 --- /dev/null +++ b/src/apps/perps/components/AgentControls.tsx @@ -0,0 +1,1248 @@ +import { useState, useEffect } from 'react'; +import { Button } from './ui/button'; +import { Card } from './ui/card'; +import { Badge } from './ui/badge'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from './ui/dialog'; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from './ui/collapsible'; +import { Input } from './ui/input'; +import { Label } from './ui/label'; +import { + Shield, + CheckCircle2, + AlertCircle, + Copy, + Download, + Upload, + Trash2, + Settings, + Lock, + ChevronDown, + Loader2, +} from 'lucide-react'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + DropdownMenuSeparator, +} from './ui/dropdown-menu'; +import { toast } from 'sonner'; +import { createWalletClient, custom } from 'viem'; +import { arbitrum } from 'viem/chains'; +import useTransactionKit from '../../../hooks/useTransactionKit'; +import { useHyperliquid } from '../hooks/useHyperliquid'; +import { privateKeyToAccount } from 'viem/accounts'; +import type { Hex } from 'viem'; +import { generateAgentWallet } from '../lib/hyperliquid/signing'; +import { + buildApproveAgentAction, + getApproveAgentTypedData, +} from '../lib/hyperliquid/signing'; +import { postExchange } from '../lib/hyperliquid/client'; +import { ValidationStatus } from './ValidationStatus'; +import { DepositModal } from './DepositModal'; +import type { UserState } from '../lib/hyperliquid/types'; +import { PinSetupModal } from './PinSetupModal'; +import { UnlockWalletModal } from './UnlockWalletModal'; +import { PrivateKeyModal } from './PrivateKeyModal'; +import { useIsMobile } from '../hooks/use-mobile'; + +import { + storeAgentWallet, + updateAgentApproval, + updateBuilderApproval, + clearAgentWallet, + storeAgentWalletEncrypted, + unlockAgentWallet, + getAgentWallet, + getAgentAddress, + isAgentWalletEncrypted, + isImportedAccountEncrypted, + getImportedAccountAddress, + getImportedAccount, + clearImportedAccount, + unlockImportedAccount, + storeImportedAccountEncrypted, +} from '../lib/hyperliquid/keystore'; +import { cn } from '../lib/utils'; + +type AgentStatus = 'none' | 'created' | 'approved' | 'locked' | 'builder_approval_pending'; + +interface AgentControlsProps { + onStatusChange?: () => void; + onAgentAddressChange?: (address: string | null) => void; + userState?: UserState; + ethPrice?: number; +} + +// Add 'unlock' to revealMode type +type RevealMode = 'copy' | 'download' | 'unlock'; + +export function AgentControls({ + onStatusChange, + onAgentAddressChange, + userState, + ethPrice, +}: AgentControlsProps) { + const { walletProvider } = useTransactionKit(); + const { address } = useHyperliquid(); + // Removed useWalletClient from wagmi + + // Calculate master balance for conditional logic + const masterBalance = userState?.marginSummary?.accountValue + ? parseFloat(userState.marginSummary.accountValue) + : 0; + const [agentStatus, setAgentStatus] = useState('none'); + const [agentAddress, setAgentAddress] = useState(''); + const [isCreating, setIsCreating] = useState(false); + const [isApproving, setIsApproving] = useState(false); + const [isLoadingAgent, setIsLoadingAgent] = useState(false); + const [agentPrivateKey, setAgentPrivateKey] = useState(''); + const [showImportDialog, setShowImportDialog] = useState(false); + const [importPrivateKey, setImportPrivateKey] = useState(''); + const [importAccountAddress, setImportAccountAddress] = useState(''); + const [isRemoving, setIsRemoving] = useState(false); + const isMobile = useIsMobile(); + const [isOpen, setIsOpen] = useState(true); + + useEffect(() => { + if (isMobile) { + if (agentStatus === 'approved') { + setIsOpen(false); + } else { + setIsOpen(true); + } + } else { + setIsOpen(true); + } + }, [isMobile, agentStatus]); + + const [validationStatus, setValidationStatus] = useState< + 'idle' | 'validating' | 'success' | 'error' + >('idle'); + const [validationData, setValidationData] = useState<{ + agentAddress?: string; + balance?: string; + openPositions?: number; + errorMessage?: string; + }>({}); + + // PIN & Encryption State + const [showPinSetup, setShowPinSetup] = useState(false); + const [showUnlockReveal, setShowUnlockReveal] = useState(false); + const [revealMode, setRevealMode] = useState<'unlock' | 'reveal'>('unlock'); // 'unlock' = just unlock, 'reveal' = show key + const [pendingImportData, setPendingImportData] = useState<{ + address: string; + privateKey: Hex; + accountState?: any; + } | null>(null); + + const [privateKeyModalState, setPrivateKeyModalState] = useState<{ + isOpen: boolean; + address: string; + privateKey: string; + mode: 'created' | 'revealed'; + }>({ + isOpen: false, + address: '', + privateKey: '', + mode: 'created', + }); + + // Check status on mount / address change + useEffect(() => { + const checkStatus = async () => { + // Priority 1: Check for unlocked imported account (memory/cache) + // We check this FIRST so that if we just created/unlocked it, we don't force a re-unlock. + const imported = getImportedAccount(); + + if (imported) { + setAgentAddress(imported.accountAddress); + setAgentPrivateKey(imported.privateKey); + setAgentStatus('approved'); + return; + } + + // Priority 2: Check for GLOBAL imported account (locked) + const isEncrypted = isImportedAccountEncrypted(); + + if (isEncrypted) { + const addr = getImportedAccountAddress(); + if (addr) { + setAgentAddress(addr); + setAgentStatus('locked'); + // Auto-prompt check + setRevealMode('unlock'); + setShowUnlockReveal(true); + return; + } + } + + // Priority 3: Check for agent wallet (if connected wallet exists) + if (!address) { + setAgentStatus('none'); + return; + } + + // 3a. Try to get unlocked agent wallet + const wallet = await getAgentWallet(address); + if (wallet) { + setAgentAddress(wallet.address); + setAgentPrivateKey(wallet.privateKey); + if (wallet.approved) { + if (wallet.builderApproved) { + setAgentStatus('approved'); + } else { + setAgentStatus('builder_approval_pending'); + } + } else { + setAgentStatus('created'); + } + return; + } + + // 3b. Check if agent wallet is locked + if (isAgentWalletEncrypted(address)) { + const addr = getAgentAddress(address); + if (addr) { + setAgentAddress(addr); + setAgentStatus('locked'); + setRevealMode('unlock'); + setShowUnlockReveal(true); + } + return; + } + + setAgentStatus('none'); + }; + + checkStatus(); + }, [address, validationStatus]); // Re-run if validation finishes (import) or address changes + + // Notify parent of agent address changes + useEffect(() => { + if (onAgentAddressChange) { + onAgentAddressChange(agentAddress || null); + } + }, [agentAddress, onAgentAddressChange]); + + // Auto-show unlock modal when wallet becomes locked + useEffect(() => { + if (agentStatus === 'locked' && !showUnlockReveal) { + setRevealMode('unlock'); + setShowUnlockReveal(true); + } + }, [agentStatus, showUnlockReveal]); + + const handleUnlockClick = () => { + setShowUnlockReveal(true); + setRevealMode('copy'); // Default mode, but actually we just want to unlock session + // We need to distinguish between "Unlock Session" and "Reveal Key". + // For now, let's just use the same modal. + // If we rename revealMode to 'unlock' | 'copy' | 'download'? + }; + + // Modify handleUnlockForReveal to handle simple unlock + const handleUnlockForReveal = async (pin: string): Promise => { + try { + // Priority 1: Try unlocking imported account + // Priority 1: Try unlocking imported account + if (isImportedAccountEncrypted()) { + const unlocked = await unlockImportedAccount(pin); + if (unlocked) { + setAgentAddress(unlocked.accountAddress); + setAgentPrivateKey(unlocked.privateKey); + setAgentStatus('approved'); + setShowUnlockReveal(false); + + // Show Key in Modal ONLY if revealed + if (revealMode === 'reveal') { + setPrivateKeyModalState({ + isOpen: true, + address: unlocked.accountAddress, + privateKey: unlocked.privateKey, + mode: 'revealed', + }); + } else { + toast.success('Wallet unlocked'); + } + + // Trigger data refresh on parent + if (onStatusChange) { + onStatusChange(); + } + + return true; + } + } + + // Priority 2: Try unlocking agent wallet (if connected) + if (!address) return false; + const unlocked = await unlockAgentWallet(address, pin); + if (unlocked) { + setAgentPrivateKey(unlocked.privateKey); + if (unlocked.approved) { + if (unlocked.builderApproved) { + setAgentStatus('approved'); + } else { + setAgentStatus('builder_approval_pending'); + } + } else { + setAgentStatus('created'); + } + setShowUnlockReveal(false); + + // Show Key in Modal ONLY if revealed + if (revealMode === 'reveal') { + setPrivateKeyModalState({ + isOpen: true, + address: unlocked.address, + privateKey: unlocked.privateKey, + mode: 'revealed', + }); + } else { + toast.success('Wallet unlocked'); // Silent unlock + } + + // Trigger data refresh on parent + if (onStatusChange) { + onStatusChange(); + } + + return true; + } + return false; + } catch (e) { + throw e; + } + }; + + const handleCreateAgentClick = () => { + if (!address) { + toast.error('Please connect your wallet first'); + return; + } + + // Proceed directly to setup - if UI shows "Create New", we assume we can create new. + // Any existing data will be overwritten. + setPendingImportData(null); + setShowPinSetup(true); + }; + + const handleAgentCreationWithPin = async (pin: string) => { + setShowPinSetup(false); + setIsCreating(true); + try { + if (pendingImportData) { + // Encrypt IMPORTED wallet as GLOBAL account + await storeImportedAccountEncrypted( + importAccountAddress.trim() || pendingImportData.address, + pendingImportData.privateKey, + pin + ); + + // Update local state immediately + setAgentAddress( + importAccountAddress.trim() || pendingImportData.address + ); + setAgentPrivateKey(pendingImportData.privateKey); + setAgentStatus('approved'); + + // Restore Validation Success Logic (Deferred from Import) + // Restore Validation Success Logic (Deferred from Import) + // Data is already set in handleImportAgent + + toast.success('✅ Account imported!', { + description: 'Agent wallet secured successfully.', + duration: 5000, + }); + + // Clear validation status now that flow is complete + setValidationStatus('idle'); + } else { + // Generate NEW wallet + + // Safety check: Verify address still exists before proceeding + if (!address) { + toast.error( + 'Wallet connection lost. Please reconnect and try again.' + ); + setIsCreating(false); + return; + } + + const wallet = generateAgentWallet(); + + await storeAgentWalletEncrypted( + address, + wallet.address, + wallet.privateKey, + pin, + false + ); + + setAgentAddress(wallet.address); + setAgentPrivateKey(wallet.privateKey); // Keep in memory for this session + setAgentStatus('created'); + + // Show Success Modal + setPrivateKeyModalState({ + isOpen: true, + address: wallet.address, + privateKey: wallet.privateKey, + mode: 'created', + }); + } + + // Trigger data refresh on parent + if (onStatusChange) { + onStatusChange(); + } + } catch (error: any) { + console.error('Agent creation/import error:', error); + toast.error('Failed to secure agent wallet'); + } finally { + setIsCreating(false); + } + }; + + + const [isApprovingBuilder, setIsApprovingBuilder] = useState(false); + + const handleApproveBuilder = async () => { + if (!address || !walletProvider) { + toast.error('Please connect your wallet'); + return; + } + setIsApprovingBuilder(true); + try { + console.log('Approving Builder...'); + const { BUILDER_ADDRESS, BUILDER_FEE_APPROVAL } = await import( + '../lib/hyperliquid/builder' + ); + + const { buildApproveBuilderFeeAction, signApproveBuilderFeeAction } = + await import('../lib/hyperliquid/signing'); + const { postExchange } = await import('../lib/hyperliquid/client'); + + // 1. Get account + let accountToUse = address as Hex; + if (walletProvider && 'request' in walletProvider) { + // Logic to ensure account (omitted for brevity, relying on address/provider match) + } + + const action = buildApproveBuilderFeeAction({ + maxFeeRate: BUILDER_FEE_APPROVAL, + builderAddress: BUILDER_ADDRESS, + nonce: Date.now(), + }); + + // 2. Sign + const signature = await signApproveBuilderFeeAction( + walletProvider as any, + action + ); + + const apiAction = { + ...action, + builder: action.builder.toLowerCase(), + }; + + const payload = { + action: apiAction, + nonce: action.nonce, + signature, + vaultAddress: null, + }; + + // 3. Post + const response = await postExchange(payload); + if (response.status === 'ok') { + toast.success('PillarX Approved!'); + + // Update local state to fully approved + updateBuilderApproval(address, true); + setAgentStatus('approved'); + + if (onStatusChange) { + onStatusChange(); + } + + } else { + throw new Error(response.response?.data?.toString() || 'Failed'); + } + + } catch (error: any) { + console.error('Failed to approve PillarX:', error); + toast.error(error.message || 'Failed to approve PillarX'); + } finally { + setIsApprovingBuilder(false); + } + }; + + const handleApproveAgent = async () => { + if (!address || !walletProvider) { + toast.error('Please connect your wallet'); + return; + } + + const agent = await getAgentWallet(address); + if (!agent) { + toast.error('No agent wallet found'); + return; + } + + if (agent.approved) { + // Check builder status + if (agent.builderApproved) { + toast.success('Agent is already approved'); + setAgentStatus('approved'); + return; + } else { + // Transition to builder pending + setAgentStatus('builder_approval_pending'); + return; + } + } + + setIsApproving(true); + try { + let accountToUse = address as Hex; + + // Probe walletProvider structure + if (walletProvider) { + // Check if we need to request accounts + if ('request' in walletProvider) { + try { + // @ts-ignore + const accounts = await walletProvider.request({ + method: 'eth_accounts', + }); + if (accounts && Array.isArray(accounts) && accounts.length > 0) { + // Use the account from the provider to ensure case match + accountToUse = accounts[0]; + } else { + console.warn( + 'No accounts found from provider. Requesting access...' + ); + // @ts-ignore + const requested = await walletProvider.request({ + method: 'eth_requestAccounts', + }); + if ( + requested && + Array.isArray(requested) && + requested.length > 0 + ) { + accountToUse = requested[0]; + } + } + } catch (e) { + console.error('Error checking accounts:', e); + } + + // Check chain ID and switch if necessary + try { + // @ts-ignore + const chainId = await walletProvider.request({ + method: 'eth_chainId', + }); + + const targetChainId = '0xa4b1'; // Arbitrum One + + if (chainId !== targetChainId) { + try { + // @ts-ignore + await walletProvider.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: targetChainId }], + }); + } catch (switchError: any) { + // This error code indicates that the chain has not been added to MetaMask. + if (switchError.code === 4902) { + // @ts-ignore + await walletProvider.request({ + method: 'wallet_addEthereumChain', + params: [ + { + chainId: targetChainId, + chainName: 'Arbitrum One', + rpcUrls: ['https://arb1.arbitrum.io/rpc'], + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + }, + blockExplorerUrls: ['https://arbiscan.io'], + }, + ], + }); + } else { + throw switchError; + } + } + } + } catch (e) { + console.error('Error switching chain:', e); + toast.error( + 'Failed to switch network. Please switch to Arbitrum manually.' + ); + setIsApproving(false); + return; + } + } + } + + const actionConfig = buildApproveAgentAction({ + agentAddress: agent.address, + nonce: Date.now(), + }); + + // Get EIP-712 typed data structures + const { domain, types, primaryType, message } = getApproveAgentTypedData( + actionConfig.hyperliquidChain, + actionConfig.signatureChainId, + actionConfig.agentAddress, + actionConfig.agentName, + actionConfig.nonce + ); + + // Note: walletProvider is already a viem WalletClient in this context + // We cast it to any/WalletClient to access signTypedData + const signature = await (walletProvider as any).signTypedData({ + account: accountToUse, + domain, + types, + primaryType, + message, + }); + + // Ensure agent address is lowercase for API + // And include signatureChainId as it is required by the API + const apiAction = { + ...actionConfig, + agentAddress: actionConfig.agentAddress.toLowerCase(), + }; + + const payload = { + action: apiAction, + nonce: actionConfig.nonce, + signature: { + r: signature.slice(0, 66), + s: '0x' + signature.slice(66, 130), + v: parseInt(signature.slice(130, 132), 16), + }, + vaultAddress: null, + }; + + const response = await postExchange(payload); + + if (response.status === 'ok') { + // Store approval status locally WITHOUT overwriting/touching the keys + updateAgentApproval(address, true); + // Transition to Builder Approval pending instead of full success + setAgentStatus('builder_approval_pending'); + toast.success('Agent approved! Now verify PillarX.'); + + if (onStatusChange) { + onStatusChange(); + } + } else { + throw new Error( + response.response?.data?.toString() || 'Approval failed' + ); + } + } catch (error: any) { + console.error('Approval error:', error); + toast.error('Failed to approve agent', { + description: error.message, + }); + } finally { + setIsApproving(false); + } + }; + + const copyAddress = () => { + if (agentAddress) { + navigator.clipboard.writeText(agentAddress); + toast.success('Agent address copied!'); + } + }; + + const copyPrivateKey = () => { + if (agentPrivateKey) { + navigator.clipboard.writeText(agentPrivateKey); + toast.success('Private key copied!'); + } else { + setRevealMode('copy'); + setShowUnlockReveal(true); + } + }; + + const downloadPrivateKey = () => { + if (agentPrivateKey) { + downloadKeyFile(agentAddress, agentPrivateKey); + } else { + setRevealMode('download'); + setShowUnlockReveal(true); + } + }; + + const downloadKeyFile = (addr: string, key: string) => { + const data = JSON.stringify( + { + address: addr, + privateKey: key, + createdAt: new Date().toISOString(), + note: 'KEEP THIS SAFE. DO NOT SHARE.', + }, + null, + 2 + ); + + const blob = new Blob([data], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `agent-wallet-${addr.slice(0, 8)}.json`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + + toast.success('Private key downloaded!'); + }; + + const handleRemoveAccount = async () => { + try { + // Clear data + clearImportedAccount(); + + // Reset all local state + setAgentAddress(''); + setAgentPrivateKey(''); + setAgentStatus('none'); + + // Close any open modals + setShowPinSetup(false); + setShowUnlockReveal(false); + setRevealMode('unlock'); // Reset default + + // Reset validation state + setValidationData({}); + // Note: Setting validationStatus to 'idle' will trigger the useEffect to run checkStatus() + // This is desired behavior - it will re-check and find 'none' (or fallback to native agent) + setValidationStatus('idle'); + + toast.success('Imported account removed'); + + // Trigger data refresh to clear displayed data + if (onStatusChange) { + onStatusChange(); + } + } catch (error: any) { + console.error('[AgentControls] Error removing account:', error); + toast.error('Failed to remove account'); + } + }; + + const handleImportAgent = async () => { + if (!importAccountAddress.trim()) { + toast.error('Please enter an account address'); + return; + } + + if (!importPrivateKey.trim()) { + toast.error('Please enter a private key'); + return; + } + + // Show loading toast and set validating status + const loadingToast = toast.loading('Validating agent credentials...'); + setValidationStatus('validating'); + setValidationData({}); + + try { + // Validate account address format + if (!importAccountAddress.trim().match(/^0x[a-fA-F0-9]{40}$/)) { + toast.dismiss(loadingToast); + toast.error('Invalid account address format'); + return; + } + + // Validate and derive address from private key + const formattedKey = importPrivateKey.trim().startsWith('0x') + ? (importPrivateKey.trim() as Hex) + : (`0x${importPrivateKey.trim()}` as Hex); + + const account = privateKeyToAccount(formattedKey); + + toast.loading('Checking Hyperliquid connection...', { id: loadingToast }); + + // Validate that the ACCOUNT ADDRESS exists on Hyperliquid (not the agent) + try { + const { getUserState } = await import('../lib/hyperliquid/client'); + const accountState = await getUserState(importAccountAddress.trim()); + + if (!accountState) { + toast.dismiss(loadingToast); + toast.error('Account address not found on Hyperliquid', { + description: + 'This address has no Hyperliquid account. Please use a valid account address.', + }); + return; + } + + toast.loading('Saving credentials...', { id: loadingToast }); + + // INSTEAD of storing immediately, we now PROMPT FOR PIN + toast.dismiss(loadingToast); + setShowImportDialog(false); + + //Set pending data + //Set pending data + setPendingImportData({ + address: account.address, + privateKey: formattedKey, + accountState: accountState, + }); + + // Show Success status immediately - BEFORE Pin Setup + const openPositions = + accountState.assetPositions?.filter( + (p: any) => parseFloat(p.position.szi) !== 0 + ).length || 0; + + setValidationStatus('success'); + setValidationData({ + agentAddress: importAccountAddress.trim() || account.address, + balance: parseFloat( + accountState.marginSummary?.totalRawUsd || '0' + ).toFixed(2), + openPositions, + }); + + // Open PIN setup + setShowPinSetup(true); + + // Notify parent validation passed (optional, keeps UI fresh) + if (onStatusChange) { + onStatusChange(); + } + } catch (validationError: any) { + toast.dismiss(loadingToast); + console.error('[Import Agent] Validation error:', validationError); + + // Set error status + setValidationStatus('error'); + setValidationData({ + errorMessage: + validationError.message || + 'Could not fetch agent data. Please check your internet connection and try again.', + }); + + toast.error('❌ Failed to connect to Hyperliquid', { + description: + validationError.message || + 'Could not fetch agent data. Please check your internet connection and try again.', + duration: 5000, + }); + return; + } + } catch (error: any) { + toast.dismiss(loadingToast); + console.error('Import error:', error); + toast.error('Invalid private key', { + description: error.message || 'Please check the format and try again', + }); + } + }; + + const handleRemoveAgent = async () => { + if (!address) { + toast.error('Please connect your wallet first'); + return; + } + + setIsRemoving(true); + try { + // Clear from remote first, then local + await clearAgentWallet(address); + + // Verify deletion + const stillExists = await getAgentWallet(address); + if (stillExists) { + throw new Error( + 'Agent wallet still exists after deletion. Please try again.' + ); + } + + // Update UI + setAgentAddress(''); + setAgentPrivateKey(''); + setAgentStatus('none'); + toast.success('Agent wallet removed from all storage'); + onStatusChange?.(); + } catch (error: any) { + console.error('Remove agent error:', error); + toast.error(error.message || 'Failed to remove agent wallet'); + } finally { + setIsRemoving(false); + } + }; + + const statusConfig = { + locked: { + icon: Lock, + label: 'Active (Locked)', + color: 'text-orange-500', + bgColor: 'bg-orange-500/10 border-orange-500/30', + }, + none: { + icon: AlertCircle, + label: 'No Agent', + color: 'text-muted-foreground', + bgColor: 'bg-muted', + }, + created: { + icon: AlertCircle, + label: 'Not Approved', + color: 'text-warning', + bgColor: 'bg-warning/10 border-warning/30', + }, + 'builder_approval_pending': { + icon: AlertCircle, + label: 'Setup Incomplete', + color: 'text-orange-500', + bgColor: 'bg-orange-500/10 border-orange-500/30', + }, + approved: { + icon: CheckCircle2, + label: 'Active', + color: 'text-success', + bgColor: 'bg-success/10 border-success/30', + }, + }; + + const config = statusConfig[agentStatus]; + const Icon = config.icon; + + // Add Lock icon import if not present (Wait, imports are at top) + // I need to add Lock to imports at top manually in first block? + // Or assume lucide-react has it (it does). + // Let's add the button for Locked state. + + return ( + + +
+
+ +

+ Perps Account: +

+ + {config.label} + +
+ {isMobile && ( + + + + )} +
+ + + {/* Validation Status Display */} + {validationStatus !== 'idle' && ( +
+ +
+ )} + + {agentStatus === 'none' && ( + <> + {!address ? null : isLoadingAgent ? ( +
+ Loading agent wallet... +
+ ) : ( + <> +
+ + +
+
+ 💡 Create a new Hyperliquid agent wallet or import your + existing one +
+ + )} + + )} + + { + setShowImportDialog(open); + if (open) { + // Pre-fill with connected wallet address when dialog opens + setImportAccountAddress(address || ''); + } + }} + > + + + Import Existing Agent + + Enter the private key of your Hyperliquid agent wallet and + specify which account address to associate it with. + + +
+
+ + setImportAccountAddress(e.target.value)} + /> +

+ This is the PillarX account that will control the agent. You + can change this to any address. +

+
+
+ + setImportPrivateKey(e.target.value)} + /> +

+ The private key of your Hyperliquid agent wallet +

+
+
+ + +
+
+
+
+ + {agentStatus === 'locked' && ( + + )} + + {agentStatus === 'created' && ( +
+ {masterBalance < 10 && userState ? ( + + Deposit $10 USDC to Trade + + } + /> + ) : ( + + )} + + +
+ + )} + + {agentStatus === 'builder_approval_pending' && ( +
+ + + + + +
+ )} + + {agentStatus === 'approved' && ( +
+
+
+
+ + + Activated Account + +
+
+ + + + + + + { + setRevealMode('reveal'); + setShowUnlockReveal(true); + }} + > + Reveal Private Key + + + + + Remove Account + + + +
+
+
+ Address: +
+
+ {agentAddress} +
+ +
+
+
+
+ )} + + setShowPinSetup(false)} + /> + + setShowUnlockReveal(false)} + /> + + + setPrivateKeyModalState({ + ...privateKeyModalState, + isOpen: false, + }) + } + /> +
+
+
+ ); +} diff --git a/src/apps/perps/components/AssetSelector.tsx b/src/apps/perps/components/AssetSelector.tsx new file mode 100644 index 00000000..0eac5172 --- /dev/null +++ b/src/apps/perps/components/AssetSelector.tsx @@ -0,0 +1,187 @@ +import { useState, useMemo } from 'react'; +import { Search, ArrowUpDown } from 'lucide-react'; +import { Input } from './ui/input'; +import { Card } from './ui/card'; +import { ScrollArea } from './ui/scroll-area'; +import { Button } from './ui/button'; +import { AssetInfo, EnhancedAsset } from '../lib/hyperliquid/types'; +import { Skeleton } from './ui/skeleton'; +import { TokenIcon } from './TokenIcon'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from './ui/dropdown-menu'; + +interface AssetSelectorProps { + selectedSymbol: string | null; + onSelect: (symbol: string, asset: AssetInfo) => void; + assets: EnhancedAsset[]; +} + +type SortBy = 'price' | 'volume' | 'change'; + +export function AssetSelector({ + selectedSymbol, + onSelect, + assets, +}: AssetSelectorProps) { + const [search, setSearch] = useState(''); + const [sortBy, setSortBy] = useState('volume'); + + // Loading state is now determined by whether assets array is empty + const isLoading = assets.length === 0; + + const filteredAndSortedAssets = useMemo(() => { + let filtered = assets; + + // Filter by search + if (search) { + const searchLower = search.toLowerCase(); + filtered = assets.filter((asset) => + asset.symbol.toLowerCase().includes(searchLower) + ); + } + + // Sort + return [...filtered].sort((a, b) => { + switch (sortBy) { + case 'price': + return b.price - a.price; + case 'volume': + return b.volume - a.volume; + case 'change': + return b.priceChangePercent - a.priceChangePercent; + default: + return 0; + } + }); + }, [assets, search, sortBy]); + + const formatPrice = (price: number): string => { + if (price >= 1000) { + return price.toLocaleString('en-US', { maximumFractionDigits: 0 }); + } + return price.toFixed(2); + }; + + const formatVolume = (volume: number): string => { + if (volume >= 1e9) { + return `$${(volume / 1e9).toFixed(1)}B`; + } + if (volume >= 1e6) { + return `$${(volume / 1e6).toFixed(1)}M`; + } + if (volume >= 1e3) { + return `$${(volume / 1e3).toFixed(1)}K`; + } + return `$${volume.toFixed(0)}`; + }; + + if (isLoading) { + return ( + +
+ + +
+
+ ); + } + + return ( + +
+
+
+ + setSearch(e.target.value)} + className="pl-10" + /> +
+ + {/* Sort Dropdown */} + + + + + + setSortBy('price')}> + Sort by Price + + setSortBy('volume')}> + Sort by Volume + + setSortBy('change')}> + Sort by Change % + + + +
+ + +
+ {filteredAndSortedAssets.map((asset) => { + const isPositive = asset.priceChangePercent >= 0; + + return ( + + ); + })} + {filteredAndSortedAssets.length === 0 && ( +
+ No assets found +
+ )} +
+
+
+
+ ); +} diff --git a/src/apps/perps/components/BalanceCard.tsx b/src/apps/perps/components/BalanceCard.tsx new file mode 100644 index 00000000..6e05f37f --- /dev/null +++ b/src/apps/perps/components/BalanceCard.tsx @@ -0,0 +1,151 @@ +import { Card } from './ui/card'; +import { RefreshCw, Plus, Minus } from 'lucide-react'; +import { useIsMobile } from '../hooks/use-mobile'; +import { Button } from './ui/button'; +import { DepositModal } from './DepositModal'; +import { WithdrawModal } from './WithdrawModal'; +import type { UserState } from '../lib/hyperliquid/types'; +import { useMemo } from 'react'; + +interface BalanceCardProps { + userState: UserState; + isLoading: boolean; + masterAddress: string; + walletClient: any; + onRefresh?: () => void; + isImported?: boolean; + ethPrice?: number; +} + +export function BalanceCard({ + userState, + isLoading, + masterAddress, + walletClient, + onRefresh, + isImported, + ethPrice, +}: BalanceCardProps) { + const accountEquity = parseFloat( + userState.marginSummary?.accountValue || '0' + ); + + // Calculate total PnL from all positions + const totalPnl = useMemo(() => { + if (!userState.assetPositions) return 0; + return userState.assetPositions.reduce((sum, pos) => { + return sum + parseFloat(pos.position.unrealizedPnl || '0'); + }, 0); + }, [userState.assetPositions]); + + const pnlPercent = + accountEquity > 0 + ? ((totalPnl / (accountEquity - totalPnl)) * 100).toFixed(2) + : '0.00'; + + const isPnlPositive = totalPnl >= 0; + + const isMobile = useIsMobile(); + + return ( + +
+
+ Perps Balance +
+
+ + + + ) : undefined + } + /> + + + + ) : undefined + } + /> + {onRefresh && ( + + )} +
+
+ +
+ {/* Main Balance */} +
+

+ $ + {accountEquity.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} +

+
+ + {/* PnL Display */} +
+
+ {isPnlPositive ? '+' : ''}$ + {totalPnl.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} +
+
+ {isPnlPositive ? '+' : ''} + {pnlPercent}% {isPnlPositive ? '↑' : '↓'} +
+
+ + {/* Note about PnL calculation */} +

+ Showing total unrealized PnL from open positions +

+
+
+ ); +} diff --git a/src/apps/perps/components/CompactHeader.tsx b/src/apps/perps/components/CompactHeader.tsx new file mode 100644 index 00000000..4172538e --- /dev/null +++ b/src/apps/perps/components/CompactHeader.tsx @@ -0,0 +1,73 @@ +import { Card } from './ui/card'; +import { Button } from './ui/button'; +import { Settings, CheckCircle2, AlertCircle } from 'lucide-react'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + DropdownMenuSeparator, +} from './ui/dropdown-menu'; + +interface CompactHeaderProps { + accountAddress: string; + balance: string; + onViewKey: () => void; + onRemove: () => void; + isConnected: boolean; +} + +export function CompactHeader({ + accountAddress, + balance, + onViewKey, + onRemove, + isConnected, +}: CompactHeaderProps) { + return ( + +
+
+ {isConnected ? ( + <> + + + {accountAddress.slice(0, 6)}...{accountAddress.slice(-4)} + + + ) : ( + <> + + + Not connected + + + )} +
+ +
+ {isConnected && ( + ${balance} + )} + + + + + + + + View Private Key + + + + Remove Account + + + +
+
+
+ ); +} diff --git a/src/apps/perps/components/ConnectButton.tsx b/src/apps/perps/components/ConnectButton.tsx new file mode 100644 index 00000000..b2586d1f --- /dev/null +++ b/src/apps/perps/components/ConnectButton.tsx @@ -0,0 +1,63 @@ +import { useAccount, useConnect, useDisconnect } from 'wagmi'; +import { Button } from './ui/button'; +import { Wallet, LogOut, AlertTriangle } from 'lucide-react'; +import { Badge } from './ui/badge'; + +export function ConnectButton() { + const { address, isConnected, chain } = useAccount(); + const { connect, connectors, isPending } = useConnect(); + const { disconnect } = useDisconnect(); + + if (isConnected && address) { + const isArbitrum = chain?.id === 42161; + + return ( +
+
+ + {address.slice(0, 6)}...{address.slice(-4)} + +
+ + {chain?.name || 'Unknown Network'} + + {!isArbitrum && ( + + + Switch to Arbitrum + + )} +
+
+ +
+ ); + } + + return ( +
+ {connectors.map((connector) => ( + + ))} +
+ ); +} diff --git a/src/apps/perps/components/CopyTile.tsx b/src/apps/perps/components/CopyTile.tsx new file mode 100644 index 00000000..b845c468 --- /dev/null +++ b/src/apps/perps/components/CopyTile.tsx @@ -0,0 +1,137 @@ +import { + Card, + CardContent, + CardHeader, + CardTitle, + CardDescription, +} from './ui/card'; +import { Badge } from './ui/badge'; +import { Button } from './ui/button'; +import { TrendingUp, TrendingDown, Target, Shield, Trophy } from 'lucide-react'; +import type { CopyTile as CopyTileType } from '../lib/hyperliquid/types'; +import { getEntryPrice } from '../lib/hyperliquid/math'; + +interface CopyTileProps { + tile: CopyTileType; + onExecute: () => void; + isExecuting: boolean; + disabled: boolean; +} + +export function CopyTile({ + tile, + onExecute, + isExecuting, + disabled, +}: CopyTileProps) { + const entryPrice = getEntryPrice(tile.entry); + const isLong = tile.side === 'long'; + + const formatPrice = (price: number | number[]) => { + if (Array.isArray(price)) { + return `$${price[0]} - $${price[1]}`; + } + return `$${price}`; + }; + + const formatTakeProfits = () => { + if (typeof tile.takeProfits === 'number') { + return `$${tile.takeProfits}`; + } + if (tile.takeProfits.length === 2 && !Array.isArray(tile.takeProfits[0])) { + return `$${tile.takeProfits[0]} - $${tile.takeProfits[1]}`; + } + return tile.takeProfits.map((tp) => `$${tp}`).join(', '); + }; + + return ( + + +
+
+ + {tile.symbol} + + {isLong ? ( + <> + + LONG + + ) : ( + <> + + SHORT + + )} + + + + Copy Trade • $10 Notional • 5× Leverage + +
+
+
+ +
+
+
+ +
+
+

Entry

+

+ {formatPrice(tile.entry)} +

+
+
+ +
+
+ +
+
+

Stop Loss

+

+ ${tile.stopLoss} +

+
+
+ +
+
+ +
+
+

Take Profits

+

+ {formatTakeProfits()} +

+
+
+
+ + + + {disabled && ( +

+ Connect wallet and setup Hyperliquid to trade +

+ )} +
+
+ ); +} diff --git a/src/apps/perps/components/DepositModal.tsx b/src/apps/perps/components/DepositModal.tsx new file mode 100644 index 00000000..24025601 --- /dev/null +++ b/src/apps/perps/components/DepositModal.tsx @@ -0,0 +1,433 @@ +import { useState, useEffect } from 'react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '../components/ui/dialog'; +import { Button } from '../components/ui/button'; +import { Input } from '../components/ui/input'; +import { Label } from '../components/ui/label'; +import { ArrowDownUp, ExternalLink } from 'lucide-react'; +import { toast } from 'sonner'; +import { ethers } from 'ethers'; +import { checkUSDCBalance } from '../lib/hyperliquid/bridge'; +import useTransactionKit from '../../../hooks/useTransactionKit'; +import { useHyperliquid } from '../hooks/useHyperliquid'; +import { erc20Abi, parseUnits } from 'viem'; +import { cn } from '../lib/utils'; + +// Contract addresses +const USDC_CONTRACT_ADDRESS = + '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' as const; +const BRIDGE_CONTRACT_ADDRESS = + '0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7' as const; + +interface DepositModalProps { + userState: any; + targetAddress?: string; + trigger?: React.ReactNode; + disabled?: boolean; + ethPrice?: number; +} + +export function DepositModal({ + userState, + targetAddress, + trigger, + disabled, + ethPrice, +}: DepositModalProps) { + const [open, setOpen] = useState(false); + const [amount, setAmount] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [arbitrumBalance, setArbitrumBalance] = useState(null); + const [arbitrumEthBalance, setArbitrumEthBalance] = useState(null); + const [txHash, setTxHash] = useState(null); + + const { kit, walletProvider } = useTransactionKit(); + const { address, walletClient } = useHyperliquid(); + const [isWrongNetwork, setIsWrongNetwork] = useState(false); + + const isAddressMatch = + !targetAddress || + !address || + targetAddress.toLowerCase() === address.toLowerCase(); + + const checkNetwork = async () => { + if (walletProvider && 'request' in walletProvider) { + try { + // @ts-ignore + const chainId = await walletProvider.request({ method: 'eth_chainId' }); + // Arbitrum One is 0xa4b1 (42161) + setIsWrongNetwork(chainId !== '0xa4b1'); + } catch (e) { + console.warn('Failed to check network', e); + } + } + }; + // ... checkNetwork ... + + const switchToArbitrum = async () => { + if (!walletProvider || !('request' in walletProvider)) return; + + try { + // @ts-ignore + await walletProvider.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: '0xa4b1' }], + }); + setIsWrongNetwork(false); + } catch (switchError: any) { + // This error code indicates that the chain has not been added to MetaMask. + if (switchError.code === 4902) { + try { + // @ts-ignore + await walletProvider.request({ + method: 'wallet_addEthereumChain', + params: [ + { + chainId: '0xa4b1', + chainName: 'Arbitrum One', + rpcUrls: ['https://arb1.arbitrum.io/rpc'], + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + }, + blockExplorerUrls: ['https://arbiscan.io'], + }, + ], + }); + setIsWrongNetwork(false); + } catch (addError) { + console.error('Failed to add Arbitrum network', addError); + } + } else { + console.error('Failed to switch to Arbitrum', switchError); + } + } + }; + + const fetchArbitrumBalance = async () => { + if (!address || !kit) return; + try { + if (!walletProvider) return; + const provider = new ethers.providers.Web3Provider(walletProvider as any); + + const balance = await checkUSDCBalance(address, provider); + setArbitrumBalance(balance); + + const ethBal = await provider.getBalance(address); + setArbitrumEthBalance(ethers.utils.formatEther(ethBal)); + } catch (error) { + console.warn('Failed to fetch Arbitrum balance', error); + } + }; + + const handleOpenChange = (newOpen: boolean) => { + setOpen(newOpen); + if (newOpen) { + checkNetwork(); + fetchArbitrumBalance(); + setTxHash(null); + } + }; + + // Check network periodically or on provider change + useEffect(() => { + if (open) { + checkNetwork(); + if (!isWrongNetwork) { + fetchArbitrumBalance(); + } + } + }, [open, walletProvider, isWrongNetwork]); + + const handleMaxClick = () => { + if (arbitrumBalance) { + setAmount(arbitrumBalance); + } + }; + + const handleDeposit = async () => { + if (isWrongNetwork) { + await switchToArbitrum(); + return; + } + + if (!amount || parseFloat(amount) <= 0) { + toast.error('Invalid Amount', { + description: 'Please enter a valid amount', + }); + return; + } + // ... existing validation ... + // Check min deposit of 5 USDC for ALL deposits + if (parseFloat(amount) < 5) { + toast.error('Amount Too Low', { + description: 'Minimum deposit is 5 USDC', + }); + return; + } + + if (!address || !walletClient) { + toast.error('Wallet Not Connected', { + description: 'Please connect your wallet', + }); + return; + } + + setIsLoading(true); + try { + // Re-check network just in case + if (walletProvider && 'request' in walletProvider) { + // @ts-ignore + const chainId = await walletProvider.request({ method: 'eth_chainId' }); + if (chainId !== '0xa4b1') { + await switchToArbitrum(); + // If switch failed or user cancelled, stop + // NOTE: switchToArbitrum handles errors but we need to check execution + // @ts-ignore + const newChainId = await walletProvider.request({ method: 'eth_chainId' }); + if (newChainId !== '0xa4b1') { + setIsLoading(false); + return; + } + } + } + + // Check ETH Balance for gas + try { + if (walletProvider) { + const provider = new ethers.providers.Web3Provider( + walletProvider as any + ); + const ethBalance = await provider.getBalance(address); + if (ethBalance.lt(ethers.utils.parseEther('0.0001'))) { + toast.error('Insufficient ETH', { + description: 'You need ETH on Arbitrum for gas fees.', + }); + setIsLoading(false); + return; + } + } + } catch (e) { + console.warn('Failed to check ETH balance:', e); + } + + const amountInWei = parseUnits(amount, 6); + + // Transfer USDC directly to bridge contract using viem walletClient + toast.info('Confirming Transaction', { + description: 'Please sign the transfer transaction in your wallet...', + }); + + const txHash = await walletClient.writeContract({ + account: address as `0x${string}`, + address: USDC_CONTRACT_ADDRESS, + abi: erc20Abi, + functionName: 'transfer', + args: [BRIDGE_CONTRACT_ADDRESS as `0x${string}`, amountInWei], + }); + + if (txHash) { + toast.success('Success!', { + description: `Bridging ${amount} USDC. It will arrive in 5-10 minutes.`, + action: { + label: 'View on Arbiscan', + onClick: () => window.open(`https://arbiscan.io/tx/${txHash}`, '_blank'), + }, + }); + setOpen(false); + setTxHash(null); + setAmount(''); + } else { + throw new Error('Transaction failed'); + } + } catch (error: any) { + console.error('Bridge error:', error); + toast.error('Bridge Failed', { + description: error.message || 'Failed to bridge USDC', + }); + } finally { + setIsLoading(false); + } + }; + + // Clean up float for display + const ethDisplay = arbitrumEthBalance ? parseFloat(arbitrumEthBalance).toFixed(4) : '0'; + + const isLowEth = arbitrumEthBalance && parseFloat(arbitrumEthBalance) < 0.0001; + + const currentBalance = userState?.marginSummary?.accountValue || '0'; + // ... +

+ Min: 0.0001 ETH +

+ + return ( + + + {trigger || ( + + )} + + + + Deposit USDC + +
+ {!isAddressMatch && ( +
+ ⚠️ +
+ Wallet Mismatch +

+ You are connected with {address?.slice(0, 6)}... but trying to + deposit to {targetAddress?.slice(0, 6)}... +
+ Please switch your wallet to the correct account to deposit + defined funds. +

+
+
+ )} + + {isWrongNetwork && ( +
+ ⚠️ +
+ Wrong Network +

+ You are not on Arbitrum One. Please switch networks to deposit. +

+ +
+
+ )} + +
+ +

+ ${parseFloat(currentBalance).toFixed(2)} +

+
+ + {/* ... Balance Section ... */} + {arbitrumBalance !== null && ( +
+
+ +

+ {parseFloat(arbitrumBalance).toFixed(2)} USDC +

+
+ +
+ +
+

+ {ethDisplay} ETH + +

+

+ Min: 0.0001 ETH +

+
+
+
+ )} + +
+
+ + +
+ setAmount(e.target.value)} + disabled={isLoading || isWrongNetwork} + step="0.01" + /> +
+ +
+
+ NOTE: + Min deposit is $5 +
+
+ Network: + Arbitrum One +
+
+ Estimated Time: + 5-10 minutes +
+
+ + + + {txHash && ( +
+ Transaction submitted + + View on Arbiscan + + +
+ )} +
+
+
+ ); +} diff --git a/src/apps/perps/components/PasteStrategyButton.tsx b/src/apps/perps/components/PasteStrategyButton.tsx new file mode 100644 index 00000000..3920a0fd --- /dev/null +++ b/src/apps/perps/components/PasteStrategyButton.tsx @@ -0,0 +1,135 @@ +import { useState } from 'react'; +import { Button } from './ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from './ui/dialog'; +import { Textarea } from './ui/textarea'; +import { Label } from './ui/label'; +import { ClipboardPaste } from 'lucide-react'; +import { toast } from 'sonner'; + +interface StrategyPayload { + orderSide: 'buy' | 'sell'; + ticker: string; + exchange: string; + entryPrice: number; + stopLoss: number; + tp1?: number; + tp2?: number; + tp3?: number; + tp4?: number; + tp5?: number; +} + +interface ParsedStrategy { + ticker: string; + side: 'long' | 'short'; + entryPrice: number; + stopLoss: number; + takeProfits: string; +} + +interface PasteStrategyButtonProps { + onStrategyPasted: (strategy: ParsedStrategy) => void; +} + +export function PasteStrategyButton({ + onStrategyPasted, +}: PasteStrategyButtonProps) { + const [isOpen, setIsOpen] = useState(false); + const [jsonInput, setJsonInput] = useState(''); + + const parseStrategy = (json: string): ParsedStrategy | null => { + try { + const payload: StrategyPayload = JSON.parse(json); + + // Validate required fields + if (!payload.ticker || !payload.orderSide || !payload.entryPrice) { + toast.error('Invalid strategy payload', { + description: + 'Missing required fields: ticker, orderSide, or entryPrice', + }); + return null; + } + + // Extract ticker symbol (remove USDT.P suffix) + const ticker = payload.ticker.replace(/USDT\.P$/i, ''); + + // Convert orderSide to long/short + const side = payload.orderSide === 'buy' ? 'long' : 'short'; + + // Collect take profits (tp1, tp2, tp3) + const tps: number[] = []; + if (payload.tp1) tps.push(payload.tp1); + if (payload.tp2) tps.push(payload.tp2); + if (payload.tp3) tps.push(payload.tp3); + + return { + ticker, + side, + entryPrice: payload.entryPrice, + stopLoss: payload.stopLoss, + takeProfits: tps.join(', '), + }; + } catch (error) { + toast.error('Invalid JSON', { + description: 'Please paste a valid JSON strategy payload', + }); + return null; + } + }; + + const handlePaste = () => { + const strategy = parseStrategy(jsonInput); + if (strategy) { + onStrategyPasted(strategy); + setIsOpen(false); + setJsonInput(''); + toast.success('Strategy loaded!', { + description: `${strategy.side.toUpperCase()} ${strategy.ticker} @ $${strategy.entryPrice}`, + }); + } + }; + + return ( + + + + + + + Paste Trading Strategy + + Paste your JSON strategy payload to auto-populate the trade form + + +
+
+ +