From 284e269bb4ec2d259cc8dbc452ff6e6b20707f63 Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Thu, 19 Sep 2024 10:41:24 +0000 Subject: [PATCH] feat: add stxer simulation --- package.json | 7 +- pnpm-lock.yaml | 375 +++++++++++++++++++++++++++++++++++++++++--- simulation/index.ts | 15 ++ simulation/stxer.ts | 313 ++++++++++++++++++++++++++++++++++++ 4 files changed, 691 insertions(+), 19 deletions(-) create mode 100644 simulation/index.ts create mode 100644 simulation/stxer.ts diff --git a/package.json b/package.json index 78f8440..20ca81f 100644 --- a/package.json +++ b/package.json @@ -11,15 +11,20 @@ "dependencies": { "@stacks/connect": "^7.2.1", "@stacks/network": "^6.10.0", + "@stacks/stacks-blockchain-api-types": "^7.14.1", + "@stacks/transactions": "^6.16.1", "alex-sdk": "^2.1.4", + "c32check": "^2.0.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "ts-clarity": "^0.0.26" }, "devDependencies": { "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "@vitejs/plugin-react": "^4.3.1", "prettier": "^3.3.2", + "tsx": "^4.19.1", "typescript": "^5.4.5", "vite": "^5.3.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81e2856..2ecdd70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,15 +14,27 @@ importers: '@stacks/network': specifier: ^6.10.0 version: 6.10.0 + '@stacks/stacks-blockchain-api-types': + specifier: ^7.14.1 + version: 7.14.1 + '@stacks/transactions': + specifier: ^6.16.1 + version: 6.16.1 alex-sdk: specifier: ^2.1.4 - version: 2.1.4(@stacks/network@6.10.0)(@stacks/transactions@6.9.0) + version: 2.1.4(@stacks/network@6.10.0)(@stacks/transactions@6.16.1) + c32check: + specifier: ^2.0.0 + version: 2.0.0 react: specifier: ^18.2.0 version: 18.2.0 react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + ts-clarity: + specifier: ^0.0.26 + version: 0.0.26(typescript@5.4.5) devDependencies: '@types/react': specifier: ^18.0.27 @@ -36,6 +48,9 @@ importers: prettier: specifier: ^3.3.2 version: 3.3.2 + tsx: + specifier: ^4.19.1 + version: 4.19.1 typescript: specifier: ^5.4.5 version: 5.4.5 @@ -175,138 +190,282 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@jridgewell/gen-mapping@0.3.3': resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} @@ -438,6 +597,9 @@ packages: '@stacks/common@6.10.0': resolution: {integrity: sha512-6x5Z7AKd9/kj3+DYE9xIDIkFLHihBH614i2wqrZIjN02WxVo063hWSjIlUxlx8P4gl6olVzlOy5LzhLJD9OP0A==} + '@stacks/common@6.16.0': + resolution: {integrity: sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg==} + '@stacks/common@6.8.1': resolution: {integrity: sha512-ewL9GLZNQYa5a/3K4xSHlHIgHkD4rwWW/QEaPId8zQIaL+1O9qCaF4LX9orNQeOmEk8kvG0x2xGV54fXKCZeWQ==} @@ -453,14 +615,17 @@ packages: '@stacks/network@6.10.0': resolution: {integrity: sha512-mbiZ8nlsyy77ndmBdaqhHXii22IFdK4ThRcOQs9j/O00DkAr04jCM4GV5Q+VLUnZ9OBoJq7yOV7Pf6jglh+0hw==} + '@stacks/network@6.16.0': + resolution: {integrity: sha512-uqz9Nb6uf+SeyCKENJN+idt51HAfEeggQKrOMfGjpAeFgZV2CR66soB/ci9+OVQR/SURvasncAz2ScI1blfS8A==} + '@stacks/profile@6.9.0': resolution: {integrity: sha512-sIR60DsAHi8C6zGqKqSe1r2hXTMHgwrJkX3fAaP3de40KeplZ2bkE+0B83yismEeU2baNc+AukyVvWJv0PfP0A==} - '@stacks/stacks-blockchain-api-types@7.3.2': - resolution: {integrity: sha512-1r0+eqEWOOo7UYrFq9HGbc02DVME3NVCW/45sNKPN31PkOMMaK59DHragPJ2QbxPFiutVDUCS924+48+o3+0Tw==} + '@stacks/stacks-blockchain-api-types@7.14.1': + resolution: {integrity: sha512-65hvhXxC+EUqHJAQsqlBCqXB+zwfxZICSKYJugdg6BCp9I9qniyfz5XyQeC4RMVo0tgEoRdS/b5ZCFo5kLWmxA==} - '@stacks/transactions@6.9.0': - resolution: {integrity: sha512-hSs9+0Ew++GwMZMgPObOx0iVCQRxkiCqI+DHdPEikAmg2utpyLh2/txHOjfSIkQHvcBfJJ6O5KphmxDP4gUqiA==} + '@stacks/transactions@6.16.1': + resolution: {integrity: sha512-yCtUM+8IN0QJbnnlFhY1wBW7Q30Cxje3Zmy8DgqdBoM/EPPWadez/8wNWFANVAMyUZeQ9V/FY+8MAw4E+pCReA==} '@stencil/core@2.22.3': resolution: {integrity: sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==} @@ -562,6 +727,14 @@ packages: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} + clarity-abi@0.0.20: + resolution: {integrity: sha512-uAkKEp84Z3LnM8qruLJyB1LP2NEGwns6Sl6zBOiKeIgTfFMm3GrQlTgkFUboVV/RQwk0dJYc72sV8pvSrtn+Sg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + clarity-codegen@0.5.2: resolution: {integrity: sha512-t0uvboeZTII7n2lgobAxcQnhyjXwbUKYdUKJA3yjoaOXPvtr5i2zFV7H1E6ZeDMfqd3vIksMPvpdFfXum9SoNQ==} hasBin: true @@ -595,6 +768,9 @@ packages: cross-fetch@3.1.8: resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -622,6 +798,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -662,6 +843,9 @@ packages: get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -788,6 +972,9 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + ripemd160-min@0.0.6: resolution: {integrity: sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==} engines: {node: '>=8'} @@ -836,6 +1023,14 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + ts-clarity@0.0.26: + resolution: {integrity: sha512-XRwLquuSTDkw6iYEpznMEEgehqaIR9t313chiiZTfvtRCq/kWYXPHQhgdTw6wJBAHsqdVPuN69enwlKtu2IQPg==} + + tsx@4.19.1: + resolution: {integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==} + engines: {node: '>=18.0.0'} + hasBin: true + typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -1082,72 +1277,144 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.23.1': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.23.1': + optional: true + '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.23.1': + optional: true + '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.23.1': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.23.1': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.23.1': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.23.1': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.23.1': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.23.1': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.23.1': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.23.1': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.23.1': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.23.1': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.23.1': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.23.1': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.23.1': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.23.1': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.23.1': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.23.1': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.23.1': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.23.1': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true + '@esbuild/win32-x64@0.23.1': + optional: true + '@jridgewell/gen-mapping@0.3.3': dependencies: '@jridgewell/set-array': 1.1.2 @@ -1255,6 +1522,11 @@ snapshots: '@types/bn.js': 5.1.2 '@types/node': 18.18.4 + '@stacks/common@6.16.0': + dependencies: + '@types/bn.js': 5.1.2 + '@types/node': 18.18.4 + '@stacks/common@6.8.1': dependencies: '@types/bn.js': 5.1.2 @@ -1270,7 +1542,7 @@ snapshots: '@stacks/connect-ui': 6.0.1 '@stacks/network': 6.10.0 '@stacks/profile': 6.9.0 - '@stacks/transactions': 6.9.0 + '@stacks/transactions': 6.16.1 jsontokens: 4.0.1 url: 0.11.3 transitivePeerDependencies: @@ -1295,25 +1567,32 @@ snapshots: transitivePeerDependencies: - encoding + '@stacks/network@6.16.0': + dependencies: + '@stacks/common': 6.16.0 + cross-fetch: 3.1.8 + transitivePeerDependencies: + - encoding + '@stacks/profile@6.9.0': dependencies: '@stacks/common': 6.8.1 '@stacks/network': 6.10.0 - '@stacks/transactions': 6.9.0 + '@stacks/transactions': 6.16.1 jsontokens: 4.0.1 schema-inspector: 2.1.0 zone-file: 2.0.0-beta.3 transitivePeerDependencies: - encoding - '@stacks/stacks-blockchain-api-types@7.3.2': {} + '@stacks/stacks-blockchain-api-types@7.14.1': {} - '@stacks/transactions@6.9.0': + '@stacks/transactions@6.16.1': dependencies: '@noble/hashes': 1.1.5 '@noble/secp256k1': 1.7.1 - '@stacks/common': 6.8.1 - '@stacks/network': 6.10.0 + '@stacks/common': 6.16.0 + '@stacks/network': 6.16.0 c32check: 2.0.0 lodash.clonedeep: 4.5.0 transitivePeerDependencies: @@ -1375,11 +1654,11 @@ snapshots: transitivePeerDependencies: - supports-color - alex-sdk@2.1.4(@stacks/network@6.10.0)(@stacks/transactions@6.9.0): + alex-sdk@2.1.4(@stacks/network@6.10.0)(@stacks/transactions@6.16.1): dependencies: '@stacks/network': 6.10.0 - '@stacks/transactions': 6.9.0 - clarity-codegen: 0.5.2(@stacks/transactions@6.9.0) + '@stacks/transactions': 6.16.1 + clarity-codegen: 0.5.2(@stacks/transactions@6.16.1) transitivePeerDependencies: - debug @@ -1424,7 +1703,7 @@ snapshots: c32check@2.0.0: dependencies: - '@noble/hashes': 1.1.5 + '@noble/hashes': 1.3.2 base-x: 4.0.0 call-bind@1.0.2: @@ -1440,10 +1719,14 @@ snapshots: escape-string-regexp: 1.0.5 supports-color: 5.5.0 - clarity-codegen@0.5.2(@stacks/transactions@6.9.0): + clarity-abi@0.0.20(typescript@5.4.5): + optionalDependencies: + typescript: 5.4.5 + + clarity-codegen@0.5.2(@stacks/transactions@6.16.1): dependencies: - '@stacks/stacks-blockchain-api-types': 7.3.2 - '@stacks/transactions': 6.9.0 + '@stacks/stacks-blockchain-api-types': 7.14.1 + '@stacks/transactions': 6.16.1 axios: 1.7.2 lodash: 4.17.21 yargs: 17.7.2 @@ -1481,6 +1764,12 @@ snapshots: transitivePeerDependencies: - encoding + cross-fetch@4.0.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + csstype@3.1.2: {} debug@4.3.4: @@ -1519,6 +1808,33 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + escalade@3.1.2: {} escape-string-regexp@1.0.5: {} @@ -1547,6 +1863,10 @@ snapshots: has-proto: 1.0.1 has-symbols: 1.0.3 + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + globals@11.12.0: {} has-flag@3.0.0: {} @@ -1635,6 +1955,8 @@ snapshots: require-directory@2.1.1: {} + resolve-pkg-maps@1.0.0: {} + ripemd160-min@0.0.6: {} rollup@4.18.0: @@ -1697,6 +2019,23 @@ snapshots: tr46@0.0.3: {} + ts-clarity@0.0.26(typescript@5.4.5): + dependencies: + '@stacks/stacks-blockchain-api-types': 7.14.1 + '@stacks/transactions': 6.16.1 + clarity-abi: 0.0.20(typescript@5.4.5) + cross-fetch: 4.0.0 + transitivePeerDependencies: + - encoding + - typescript + + tsx@4.19.1: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + typescript@5.4.5: {} update-browserslist-db@1.0.16(browserslist@4.23.1): diff --git a/simulation/index.ts b/simulation/index.ts new file mode 100644 index 0000000..20c3c60 --- /dev/null +++ b/simulation/index.ts @@ -0,0 +1,15 @@ +import { AlexSDK, Currency } from "alex-sdk"; +import { SimulationBuilder } from "./stxer"; + +const sdk = new AlexSDK() +const addr = "SP212Y5JKN59YP3GYG07K3S8W5SSGE4KH6B5STXER" +const tx = await sdk.runSwap(addr, Currency.STX, Currency.ALEX, BigInt(1e8), 0n) + +await SimulationBuilder.new() + .withSender(addr) + .addContractCall({ + contract_id: `${tx.contractAddress}.${tx.contractName}`, + function_name: tx.functionName, + function_args: tx.functionArgs + }) + .run() diff --git a/simulation/stxer.ts b/simulation/stxer.ts new file mode 100644 index 0000000..87b7113 --- /dev/null +++ b/simulation/stxer.ts @@ -0,0 +1,313 @@ +import { AccountDataResponse, getNodeInfo, richFetch } from 'ts-clarity'; +import { Block } from '@stacks/stacks-blockchain-api-types'; +import { StacksMainnet } from '@stacks/network'; +import { + AnchorMode, + ClarityValue, + PostConditionMode, + type StacksTransaction, + bufferCV, + contractPrincipalCV, + makeUnsignedContractCall, + makeUnsignedContractDeploy, + makeUnsignedSTXTokenTransfer, + serializeCV, + stringAsciiCV, + tupleCV, + uintCV, +} from '@stacks/transactions'; +import { c32addressDecode } from 'c32check'; + +// current beta api endpoint +const SIMULATION_API_ENDPOINT = 'https://api.stxer.xyz/simulations'; + +function runTx(tx: StacksTransaction) { + // type 0: run transaction + return tupleCV({ type: uintCV(0), data: bufferCV(tx.serialize()) }); +} + +export interface SimulationEval { + contract_id: string; + code: string; +} + +export function runEval({ contract_id, code }: SimulationEval) { + const [contract_address, contract_name] = contract_id.split('.'); + // type 1: eval arbitrary code inside a contract + return tupleCV({ + type: uintCV(1), + data: bufferCV( + serializeCV( + tupleCV({ + contract: contractPrincipalCV(contract_address, contract_name), + code: stringAsciiCV(code), + }) + ) + ), + }); +} + +export async function runSimulation( + block_hash: string, + block_height: number, + txs: (StacksTransaction | SimulationEval)[] +) { + const body = Buffer.concat([ + Buffer.from('sim-v1'), + Buffer.alloc(8), + Buffer.from( + block_hash.startsWith('0x') ? block_hash.substring(2) : block_hash, + 'hex' + ), + ...txs + .map((t) => { + return 'contract_id' in t && 'code' in t ? runEval(t) : runTx(t); + }) + .map((t) => serializeCV(t)), + ]); + body.writeBigUInt64BE(BigInt(block_height), 6); + const rs = await fetch(SIMULATION_API_ENDPOINT, { + method: 'POST', + body, + }).then(async (rs) => { + const response = await rs.text(); + if (!response.startsWith('{')) { + throw new Error(`failed to submit simulation: ${response}`); + } + // console.log(response); + return JSON.parse(response) as { id: string }; + }); + return rs.id; +} + +export class SimulationBuilder { + public static new() { + return new SimulationBuilder(); + } + private block = NaN; + private sender = ''; + private steps: ( + | { + // contract call + contract_id: string; + function_name: string; + function_args?: ClarityValue[]; + sender: string; + fee: number; + } + | { + // contract deploy + contract_name: string; + source_code: string; + deployer: string; + fee: number; + } + | { + // STX transfer + recipient: string; + amount: number; + sender: string; + fee: number; + } + | SimulationEval + )[] = []; + + public useBlockHeight(block: number) { + this.block = block; + return this; + } + public withSender(address: string) { + this.sender = address; + return this; + } + public addSTXTransfer(params: { + recipient: string; + amount: number; + sender?: string; + fee?: number; + }) { + if (params.sender == null && this.sender === '') { + throw new Error( + 'Please specify a sender with useSender or adding a sender paramenter' + ); + } + this.steps.push({ + ...params, + sender: params.sender ?? this.sender, + fee: params.fee ?? 0, + }); + return this; + } + public addContractCall(params: { + contract_id: string; + function_name: string; + function_args?: ClarityValue[]; + sender?: string; + fee?: number; + }) { + if (params.sender == null && this.sender === '') { + throw new Error( + 'Please specify a sender with useSender or adding a sender paramenter' + ); + } + this.steps.push({ + ...params, + sender: params.sender ?? this.sender, + fee: params.fee ?? 0, + }); + return this; + } + public addContractDeploy(params: { + contract_name: string; + source_code: string; + deployer?: string; + fee?: number; + }) { + if (params.deployer == null && this.sender === '') { + throw new Error( + 'Please specify a deployer with useSender or adding a deployer paramenter' + ); + } + this.steps.push({ + ...params, + deployer: params.deployer ?? this.sender, + fee: params.fee ?? 0, + }); + return this; + } + public addEvalCode(inside_contract_id: string, code: string) { + this.steps.push({ + contract_id: inside_contract_id, + code, + }); + return this; + } + public addMapRead(contract_id: string, map: string, key: string) { + this.steps.push({ + contract_id, + code: `(map-get ${map} ${key})`, + }); + return this; + } + public addVarRead(contract_id: string, variable: string) { + this.steps.push({ + contract_id, + code: `(var-get ${variable})`, + }); + return this; + } + + private async getBlockInfo() { + if (Number.isNaN(this.block)) { + const { stacks_tip_height } = await getNodeInfo(); + this.block = stacks_tip_height; + } + const info: Block = await richFetch( + `https://api.hiro.so/extended/v1/block/by_height/${this.block}?unanchored=true` + ).then((r) => r.json()); + if ( + info.height !== this.block || + typeof info.hash !== 'string' || + !info.hash.startsWith('0x') + ) { + throw new Error( + `failed to get block info for block height ${this.block}` + ); + } + return { + block_height: this.block, + block_hash: info.hash.substring(2), + index_block_hash: info.index_block_hash.substring(2), + }; + } + + public async run() { + console.log( + `-------------------------------- +This product can never exist without your support! + +We receive sponsorship funds with: +SP212Y5JKN59YP3GYG07K3S8W5SSGE4KH6B5STXER + +Feedbacks and feature requests are welcome. +To get in touch: contact@stxer.xyz +--------------------------------` + ); + const block = await this.getBlockInfo(); + console.log( + `Using block height ${block.block_height} hash 0x${block.block_hash} to run simulation.` + ); + const txs: (StacksTransaction | SimulationEval)[] = []; + const nonce_by_address = new Map(); + const nextNonce = async (sender: string) => { + let nonce = nonce_by_address.get(sender); + if (nonce == null) { + const url = `https://api.hiro.so/v2/accounts/${sender}?proof=${false}&tip=${block.index_block_hash + }`; + const account: AccountDataResponse = await richFetch(url).then((r) => + r.json() + ); + nonce_by_address.set(sender, account.nonce + 1); + return account.nonce; + } + nonce_by_address.set(sender, nonce + 1); + return nonce; + }; + for (const step of this.steps) { + if ('sender' in step && 'function_name' in step) { + const nonce = await nextNonce(step.sender); + const [contractAddress, contractName] = step.contract_id.split('.'); + const tx = await makeUnsignedContractCall({ + contractAddress, + contractName, + functionName: step.function_name, + functionArgs: step.function_args ?? [], + nonce, + network: new StacksMainnet(), + publicKey: '', + postConditionMode: PostConditionMode.Allow, + anchorMode: AnchorMode.Any, + fee: step.fee, + }); + tx.auth.spendingCondition.signer = c32addressDecode(step.sender)[1]; + txs.push(tx); + } else if ('sender' in step && 'recipient' in step) { + const nonce = await nextNonce(step.sender); + const tx = await makeUnsignedSTXTokenTransfer({ + recipient: step.recipient, + amount: step.amount, + nonce, + network: new StacksMainnet(), + publicKey: '', + anchorMode: AnchorMode.Any, + fee: step.fee, + }); + tx.auth.spendingCondition.signer = c32addressDecode(step.sender)[1]; + txs.push(tx); + } else if ('deployer' in step) { + const nonce = await nextNonce(step.deployer); + const tx = await makeUnsignedContractDeploy({ + contractName: step.contract_name, + codeBody: step.source_code, + nonce, + network: new StacksMainnet(), + publicKey: '', + postConditionMode: PostConditionMode.Allow, + anchorMode: AnchorMode.Any, + fee: step.fee, + }); + tx.auth.spendingCondition.signer = c32addressDecode(step.deployer)[1]; + txs.push(tx); + } else if ('code' in step) { + txs.push(step); + } else { + console.log(`Invalid simulation step:`, step); + } + } + const id = await runSimulation(block.block_hash, block.block_height, txs); + console.log( + `Simulation will be available at: https://stxer.xyz/simulations/mainnet/${id}` + ); + return id; + } +}