From 8b207d07e4b92bc5692e470d5532e08b10052903 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:00:19 -0400 Subject: [PATCH 001/191] add hats-module sdk --- package-lock.json | 254 +++++++++++++++++++++++++++------------------- package.json | 3 +- 2 files changed, 154 insertions(+), 103 deletions(-) diff --git a/package-lock.json b/package-lock.json index b013d5feea..7395ce5d97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@fontsource/space-mono": "^5.0.19", "@fractal-framework/fractal-contracts": "^1.2.14", "@graphprotocol/client-apollo": "^1.0.16", + "@hatsprotocol/modules-sdk": "^1.4.0", "@hatsprotocol/sdk-v1-core": "^0.9.0", "@hatsprotocol/sdk-v1-subgraph": "^1.0.0", "@hotjar/browser": "^1.0.9", @@ -67,7 +68,7 @@ "remark-gfm": "^4.0.0", "sonner": "^1.5.0", "viem": "^2.13.1", - "vite": "^5.3.4", + "vite": "5.1.0", "vite-plugin-checker": "^0.6.4", "wagmi": "^2.12.12", "yup": "^1.4.0", @@ -3700,12 +3701,13 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "aix" @@ -3715,12 +3717,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -3730,12 +3733,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -3745,12 +3749,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -3760,12 +3765,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3775,12 +3781,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3790,12 +3797,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3805,12 +3813,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3820,12 +3829,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3835,12 +3845,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3850,12 +3861,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3865,12 +3877,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", "cpu": [ "loong64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3880,12 +3893,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", "cpu": [ "mips64el" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3895,12 +3909,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3910,12 +3925,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3925,12 +3941,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3940,12 +3957,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3955,12 +3973,13 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -3970,12 +3989,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3985,12 +4005,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "sunos" @@ -4000,12 +4021,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -4015,12 +4037,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -4030,12 +4053,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -7362,6 +7386,30 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hatsprotocol/modules-sdk": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@hatsprotocol/modules-sdk/-/modules-sdk-1.4.0.tgz", + "integrity": "sha512-j9taBBNSTJWGuJq/vmURHJFyvG8jb3xq0xAbs22fZV/aQlkNB/7uHJ7ZT1Q0ZWGy0fjYOxw1ATWZhY1MnIt6gA==", + "license": "MIT", + "dependencies": { + "axios": "^1.5.0", + "zod": "^3.21.4" + }, + "peerDependencies": { + "viem": "^1.11.0 || ^2.0.0" + } + }, + "node_modules/@hatsprotocol/modules-sdk/node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/@hatsprotocol/sdk-v1-core": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@hatsprotocol/sdk-v1-core/-/sdk-v1-core-0.9.0.tgz", @@ -15152,10 +15200,11 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -15163,29 +15212,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" } }, "node_modules/escalade": { @@ -42456,13 +42505,14 @@ } }, "node_modules/vite": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.4.tgz", - "integrity": "sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.0.tgz", + "integrity": "sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==", + "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" }, "bin": { "vite": "bin/vite.js" diff --git a/package.json b/package.json index 073be648d6..3f6c7571c5 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@fontsource/space-mono": "^5.0.19", "@fractal-framework/fractal-contracts": "^1.2.14", "@graphprotocol/client-apollo": "^1.0.16", + "@hatsprotocol/modules-sdk": "^1.4.0", "@hatsprotocol/sdk-v1-core": "^0.9.0", "@hatsprotocol/sdk-v1-subgraph": "^1.0.0", "@hotjar/browser": "^1.0.9", @@ -61,7 +62,7 @@ "remark-gfm": "^4.0.0", "sonner": "^1.5.0", "viem": "^2.13.1", - "vite": "^5.3.4", + "vite": "5.1.0", "vite-plugin-checker": "^0.6.4", "wagmi": "^2.12.12", "yup": "^1.4.0", From e747990959c25eed35fc6082ec21ce8d4058cd0d Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:01:41 -0400 Subject: [PATCH 002/191] add abis --- .../abi/DecentAutonomousAdminTempAbi.ts | 87 +++++ src/assets/abi/DecentHatsV2TempAbi.ts | 340 ++++++++++++++++++ src/assets/abi/HatsElectionsEligibilityAbi.ts | 235 ++++++++++++ 3 files changed, 662 insertions(+) create mode 100644 src/assets/abi/DecentAutonomousAdminTempAbi.ts create mode 100644 src/assets/abi/DecentHatsV2TempAbi.ts create mode 100644 src/assets/abi/HatsElectionsEligibilityAbi.ts diff --git a/src/assets/abi/DecentAutonomousAdminTempAbi.ts b/src/assets/abi/DecentAutonomousAdminTempAbi.ts new file mode 100644 index 0000000000..c53738d0d1 --- /dev/null +++ b/src/assets/abi/DecentAutonomousAdminTempAbi.ts @@ -0,0 +1,87 @@ +export default [ + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "setUp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "currentWearer", + "type": "address" + }, + { + "internalType": "contract IHats", + "name": "userHatProtocol", + "type": "address" + }, + { + "internalType": "uint256", + "name": "userHatId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "nominatedWearer", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "streamId", + "type": "uint256" + }, + { + "internalType": "contract ISablierV2LockupLinear", + "name": "sablierV2LockupLinear", + "type": "address" + } + ], + "internalType": "struct DecentAutonomousAdmin.SablierStreamInfo[]", + "name": "sablierStreamInfo", + "type": "tuple[]" + } + ], + "internalType": "struct DecentAutonomousAdmin.TriggerStartArgs", + "name": "args", + "type": "tuple" + } + ], + "name": "triggerStartNextTerm", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version_", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] as const; diff --git a/src/assets/abi/DecentHatsV2TempAbi.ts b/src/assets/abi/DecentHatsV2TempAbi.ts new file mode 100644 index 0000000000..0de2402d2c --- /dev/null +++ b/src/assets/abi/DecentHatsV2TempAbi.ts @@ -0,0 +1,340 @@ +export const DecentHatsTempAbi = [ + { + inputs: [], + name: 'NAME', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'contract IHats', + name: 'hatsProtocol', + type: 'address', + }, + { + internalType: 'contract IERC6551Registry', + name: 'registry', + type: 'address', + }, + { + internalType: 'contract IHatsModuleFactory', + name: 'hatsModuleFactory', + type: 'address', + }, + { + internalType: 'contract ModuleProxyFactory', + name: 'moduleProxyFactory', + type: 'address', + }, + { + internalType: 'address', + name: 'decentAutonomousAdminMasterCopy', + type: 'address', + }, + { + internalType: 'address', + name: 'hatsAccountImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'keyValuePairs', + type: 'address', + }, + { + internalType: 'address', + name: 'hatsElectionEligibilityImplementation', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'wearer', + type: 'address', + }, + { + internalType: 'string', + name: 'details', + type: 'string', + }, + { + internalType: 'string', + name: 'imageURI', + type: 'string', + }, + { + components: [ + { + internalType: 'contract ISablierV2LockupLinear', + name: 'sablier', + type: 'address', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + { + components: [ + { + internalType: 'uint40', + name: 'start', + type: 'uint40', + }, + { + internalType: 'uint40', + name: 'cliff', + type: 'uint40', + }, + { + internalType: 'uint40', + name: 'end', + type: 'uint40', + }, + ], + internalType: 'struct LockupLinear.Timestamps', + name: 'timestamps', + type: 'tuple', + }, + { + components: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + { + internalType: 'uint256', + name: 'fee', + type: 'uint256', + }, + ], + internalType: 'struct LockupLinear.Broker', + name: 'broker', + type: 'tuple', + }, + { + internalType: 'uint128', + name: 'totalAmount', + type: 'uint128', + }, + { + internalType: 'bool', + name: 'cancelable', + type: 'bool', + }, + { + internalType: 'bool', + name: 'transferable', + type: 'bool', + }, + ], + internalType: 'struct DecentHats_0_2_0.SablierStreamParams[]', + name: 'sablierParams', + type: 'tuple[]', + }, + { + components: [ + { + internalType: 'uint128', + name: 'termEndDateTs', + type: 'uint128', + }, + { + internalType: 'address[]', + name: 'nominatedWearers', + type: 'address[]', + }, + ], + internalType: 'struct DecentHats_0_2_0.TermedParams[]', + name: 'termedParams', + type: 'tuple[]', + }, + { + internalType: 'uint32', + name: 'maxSupply', + type: 'uint32', + }, + { + internalType: 'bool', + name: 'isMutable', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isTermed', + type: 'bool', + }, + ], + internalType: 'struct DecentHats_0_2_0.Hat', + name: 'adminHat', + type: 'tuple', + }, + { + components: [ + { + internalType: 'address', + name: 'wearer', + type: 'address', + }, + { + internalType: 'string', + name: 'details', + type: 'string', + }, + { + internalType: 'string', + name: 'imageURI', + type: 'string', + }, + { + components: [ + { + internalType: 'contract ISablierV2LockupLinear', + name: 'sablier', + type: 'address', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + { + components: [ + { + internalType: 'uint40', + name: 'start', + type: 'uint40', + }, + { + internalType: 'uint40', + name: 'cliff', + type: 'uint40', + }, + { + internalType: 'uint40', + name: 'end', + type: 'uint40', + }, + ], + internalType: 'struct LockupLinear.Timestamps', + name: 'timestamps', + type: 'tuple', + }, + { + components: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + { + internalType: 'uint256', + name: 'fee', + type: 'uint256', + }, + ], + internalType: 'struct LockupLinear.Broker', + name: 'broker', + type: 'tuple', + }, + { + internalType: 'uint128', + name: 'totalAmount', + type: 'uint128', + }, + { + internalType: 'bool', + name: 'cancelable', + type: 'bool', + }, + { + internalType: 'bool', + name: 'transferable', + type: 'bool', + }, + ], + internalType: 'struct DecentHats_0_2_0.SablierStreamParams[]', + name: 'sablierParams', + type: 'tuple[]', + }, + { + components: [ + { + internalType: 'uint128', + name: 'termEndDateTs', + type: 'uint128', + }, + { + internalType: 'address[]', + name: 'nominatedWearers', + type: 'address[]', + }, + ], + internalType: 'struct DecentHats_0_2_0.TermedParams[]', + name: 'termedParams', + type: 'tuple[]', + }, + { + internalType: 'uint32', + name: 'maxSupply', + type: 'uint32', + }, + { + internalType: 'bool', + name: 'isMutable', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isTermed', + type: 'bool', + }, + ], + internalType: 'struct DecentHats_0_2_0.Hat[]', + name: 'hats', + type: 'tuple[]', + }, + { + internalType: 'string', + name: 'topHatDetails', + type: 'string', + }, + { + internalType: 'string', + name: 'topHatImageURI', + type: 'string', + }, + ], + internalType: 'struct DecentHats_0_2_0.CreateTreeParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'createAndDeclareTree', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const; diff --git a/src/assets/abi/HatsElectionsEligibilityAbi.ts b/src/assets/abi/HatsElectionsEligibilityAbi.ts new file mode 100644 index 0000000000..f47dda9849 --- /dev/null +++ b/src/assets/abi/HatsElectionsEligibilityAbi.ts @@ -0,0 +1,235 @@ +export const HatsElectionsEligibilityAbi = [ + { + inputs: [{ internalType: 'string', name: '_version', type: 'string' }], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'uint128', name: 'termEnd', type: 'uint128' }], + name: 'ElectionClosed', + type: 'error', + }, + { inputs: [], name: 'InvalidTermEnd', type: 'error' }, + { inputs: [], name: 'NextTermNotReady', type: 'error' }, + { inputs: [], name: 'NotAdmin', type: 'error' }, + { inputs: [], name: 'NotBallotBox', type: 'error' }, + { inputs: [], name: 'NotElected', type: 'error' }, + { inputs: [], name: 'TermEnded', type: 'error' }, + { inputs: [], name: 'TermNotEnded', type: 'error' }, + { inputs: [], name: 'TooManyWinners', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint128', + name: 'termEnd', + type: 'uint128', + }, + { + indexed: false, + internalType: 'address[]', + name: 'winners', + type: 'address[]', + }, + ], + name: 'ElectionCompleted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint128', + name: 'nextTermEnd', + type: 'uint128', + }, + ], + name: 'ElectionOpened', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint8', + name: 'version', + type: 'uint8', + }, + ], + name: 'Initialized', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint128', + name: 'termEnd', + type: 'uint128', + }, + ], + name: 'NewTermStarted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint128', + name: 'termEnd', + type: 'uint128', + }, + { + indexed: false, + internalType: 'address[]', + name: 'accounts', + type: 'address[]', + }, + ], + name: 'Recalled', + type: 'event', + }, + { + inputs: [], + name: 'ADMIN_HAT', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'BALLOT_BOX_HAT', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'HATS', + outputs: [{ internalType: 'contract IHats', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'IMPLEMENTATION', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'currentTermEnd', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint128', name: '_termEnd', type: 'uint128' }, + { internalType: 'address[]', name: '_winners', type: 'address[]' }, + ], + name: 'elect', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint128', name: 'termEnd', type: 'uint128' }, + { internalType: 'address', name: 'candidates', type: 'address' }, + ], + name: 'electionResults', + outputs: [{ internalType: 'bool', name: 'elected', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint128', name: 'termEnd', type: 'uint128' }], + name: 'electionStatus', + outputs: [{ internalType: 'bool', name: 'isElectionOpen', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: '_wearer', type: 'address' }, + { internalType: 'uint256', name: '', type: 'uint256' }, + ], + name: 'getWearerStatus', + outputs: [ + { internalType: 'bool', name: 'eligible', type: 'bool' }, + { internalType: 'bool', name: 'standing', type: 'bool' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'hatId', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'nextTermEnd', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint128', name: '_termEnd', type: 'uint128' }, + { + internalType: 'address[]', + name: '_recallees', + type: 'address[]', + }, + ], + name: 'recall', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint128', name: '_newTermEnd', type: 'uint128' }], + name: 'setNextTerm', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: '_initData', type: 'bytes' }], + name: 'setUp', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'startNextTerm', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'version', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'version_', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function', + }, +] as const; From 00bb10e9a163447ad27417e26d578ed150f4e61e Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:02:28 -0400 Subject: [PATCH 003/191] update network with new contracts - temp placeholder for networks not yet deployed --- src/providers/NetworkConfig/networks/base.ts | 5 ++++- src/providers/NetworkConfig/networks/mainnet.ts | 5 ++++- src/providers/NetworkConfig/networks/optimism.ts | 5 ++++- src/providers/NetworkConfig/networks/polygon.ts | 5 ++++- src/providers/NetworkConfig/networks/sepolia.ts | 5 +++-- src/types/network.ts | 6 ++++-- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/providers/NetworkConfig/networks/base.ts b/src/providers/NetworkConfig/networks/base.ts index d7f3091656..95fdd45bd8 100644 --- a/src/providers/NetworkConfig/networks/base.ts +++ b/src/providers/NetworkConfig/networks/base.ts @@ -80,7 +80,10 @@ export const baseConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), - decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), + // @todo update addresses when contracts are deployed + decentHatsV2MasterCopy: getAddress('0x0'), + decentAutonomousAdminMasterCopy: getAddress('0x0'), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/mainnet.ts b/src/providers/NetworkConfig/networks/mainnet.ts index e17a8ffacc..1363ac194d 100644 --- a/src/providers/NetworkConfig/networks/mainnet.ts +++ b/src/providers/NetworkConfig/networks/mainnet.ts @@ -80,7 +80,10 @@ export const mainnetConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), - decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), + // @todo update addresses when contracts are deployed + decentHatsV2MasterCopy: getAddress('0x0'), + decentAutonomousAdminMasterCopy: getAddress('0x0'), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/optimism.ts b/src/providers/NetworkConfig/networks/optimism.ts index a958d90064..863f13133c 100644 --- a/src/providers/NetworkConfig/networks/optimism.ts +++ b/src/providers/NetworkConfig/networks/optimism.ts @@ -80,7 +80,10 @@ export const optimismConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), - decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), + // @todo update addresses when contracts are deployed + decentHatsV2MasterCopy: getAddress('0x0'), + decentAutonomousAdminMasterCopy: getAddress('0x0'), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/polygon.ts b/src/providers/NetworkConfig/networks/polygon.ts index afd6338946..16d441cbf0 100644 --- a/src/providers/NetworkConfig/networks/polygon.ts +++ b/src/providers/NetworkConfig/networks/polygon.ts @@ -80,7 +80,10 @@ export const polygonConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), - decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), + // @todo update addresses when contracts are deployed + decentHatsV2MasterCopy: getAddress('0x0'), + decentAutonomousAdminMasterCopy: getAddress('0x0'), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/sepolia.ts b/src/providers/NetworkConfig/networks/sepolia.ts index 330576da6c..4dcd149850 100644 --- a/src/providers/NetworkConfig/networks/sepolia.ts +++ b/src/providers/NetworkConfig/networks/sepolia.ts @@ -80,8 +80,8 @@ export const sepoliaConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), - decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), - + decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), + decentHatsV2MasterCopy: getAddress('0xaFdD339cE4Ed6638a5fba3147a2F0e4EF6d5f67a'), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', @@ -89,6 +89,7 @@ export const sepoliaConfig: NetworkConfig = { sablierV2LockupDynamic: '0x73BB6dD3f5828d60F8b3dBc8798EB10fbA2c5636', sablierV2LockupTranched: '0x3a1beA13A8C24c0EA2b8fAE91E4b2762A59D7aF5', sablierV2LockupLinear: '0x3E435560fd0a03ddF70694b35b673C25c65aBB6C', + decentAutonomousAdminMasterCopy: getAddress('0xd8784CEeC9cbA6c7eF31849Dd2c708c2AFc37b36'), }, staking: {}, moralis: { diff --git a/src/types/network.ts b/src/types/network.ts index 52241cdbd6..c13af68791 100644 --- a/src/types/network.ts +++ b/src/types/network.ts @@ -55,8 +55,9 @@ export type NetworkConfig = { fractalRegistry: Address; keyValuePairs: Address; - decentHatsMasterCopy: Address; - + decentHatsV1MasterCopy: Address; + decentHatsV2MasterCopy?: Address; + hatsProtocol: Address; erc6551Registry: Address; hatsAccount1ofNMasterCopy: Address; @@ -64,6 +65,7 @@ export type NetworkConfig = { sablierV2LockupDynamic: Address; sablierV2LockupTranched: Address; sablierV2LockupLinear: Address; + decentAutonomousAdminMasterCopy: Address; }; staking: { lido?: { From 63ca4f84239fe50eca45c0ae89bb48858b288ef4 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 11 Oct 2024 19:57:38 -0400 Subject: [PATCH 004/191] ABI and typing update --- src/assets/abi/DecentHatsTempAbi.ts | 353 ++++++++++++++++++++++++++ src/assets/abi/DecentHatsV2TempAbi.ts | 340 ------------------------- src/hooks/DAO/loaders/useHatsTree.ts | 6 +- src/store/roles/rolesStoreUtils.ts | 46 ++-- src/store/roles/useRolesStore.ts | 1 - 5 files changed, 374 insertions(+), 372 deletions(-) create mode 100644 src/assets/abi/DecentHatsTempAbi.ts delete mode 100644 src/assets/abi/DecentHatsV2TempAbi.ts diff --git a/src/assets/abi/DecentHatsTempAbi.ts b/src/assets/abi/DecentHatsTempAbi.ts new file mode 100644 index 0000000000..fbee18c969 --- /dev/null +++ b/src/assets/abi/DecentHatsTempAbi.ts @@ -0,0 +1,353 @@ +export const DecentHatsTempAbi = [ + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SALT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IHats", + "name": "hatsProtocol", + "type": "address" + }, + { + "internalType": "contract IERC6551Registry", + "name": "registry", + "type": "address" + }, + { + "internalType": "contract IHatsModuleFactory", + "name": "hatsModuleFactory", + "type": "address" + }, + { + "internalType": "contract ModuleProxyFactory", + "name": "moduleProxyFactory", + "type": "address" + }, + { + "internalType": "address", + "name": "decentAutonomousAdminMasterCopy", + "type": "address" + }, + { + "internalType": "address", + "name": "hatsAccountImplementation", + "type": "address" + }, + { + "internalType": "address", + "name": "keyValuePairs", + "type": "address" + }, + { + "internalType": "address", + "name": "hatsElectionEligibilityImplementation", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "wearer", + "type": "address" + }, + { + "internalType": "string", + "name": "details", + "type": "string" + }, + { + "internalType": "string", + "name": "imageURI", + "type": "string" + }, + { + "components": [ + { + "internalType": "address", + "name": "sablierV2LockupLinear", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint40", + "name": "start", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "cliff", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "end", + "type": "uint40" + } + ], + "internalType": "struct LockupLinear.Timestamps", + "name": "timestamps", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "UD60x18", + "name": "fee", + "type": "uint256" + } + ], + "internalType": "struct Broker", + "name": "broker", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "totalAmount", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "cancelable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "transferable", + "type": "bool" + } + ], + "internalType": "struct DecentHats.SablierStreamParams[]", + "name": "sablierParams", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint128", + "name": "termEndDateTs", + "type": "uint128" + }, + { + "internalType": "address[]", + "name": "nominatedWearers", + "type": "address[]" + } + ], + "internalType": "struct DecentHats.TermedParams[]", + "name": "termedParams", + "type": "tuple[]" + }, + { + "internalType": "uint32", + "name": "maxSupply", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "isMutable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isTermed", + "type": "bool" + } + ], + "internalType": "struct DecentHats.Hat", + "name": "adminHat", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "wearer", + "type": "address" + }, + { + "internalType": "string", + "name": "details", + "type": "string" + }, + { + "internalType": "string", + "name": "imageURI", + "type": "string" + }, + { + "components": [ + { + "internalType": "address", + "name": "sablierV2LockupLinear", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint40", + "name": "start", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "cliff", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "end", + "type": "uint40" + } + ], + "internalType": "struct LockupLinear.Timestamps", + "name": "timestamps", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "UD60x18", + "name": "fee", + "type": "uint256" + } + ], + "internalType": "struct Broker", + "name": "broker", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "totalAmount", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "cancelable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "transferable", + "type": "bool" + } + ], + "internalType": "struct DecentHats.SablierStreamParams[]", + "name": "sablierParams", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint128", + "name": "termEndDateTs", + "type": "uint128" + }, + { + "internalType": "address[]", + "name": "nominatedWearers", + "type": "address[]" + } + ], + "internalType": "struct DecentHats.TermedParams[]", + "name": "termedParams", + "type": "tuple[]" + }, + { + "internalType": "uint32", + "name": "maxSupply", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "isMutable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isTermed", + "type": "bool" + } + ], + "internalType": "struct DecentHats.Hat[]", + "name": "hats", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "topHatDetails", + "type": "string" + }, + { + "internalType": "string", + "name": "topHatImageURI", + "type": "string" + } + ], + "internalType": "struct DecentHats.CreateTreeParams", + "name": "params", + "type": "tuple" + } + ], + "name": "createAndDeclareTree", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] as const; diff --git a/src/assets/abi/DecentHatsV2TempAbi.ts b/src/assets/abi/DecentHatsV2TempAbi.ts deleted file mode 100644 index 0de2402d2c..0000000000 --- a/src/assets/abi/DecentHatsV2TempAbi.ts +++ /dev/null @@ -1,340 +0,0 @@ -export const DecentHatsTempAbi = [ - { - inputs: [], - name: 'NAME', - outputs: [ - { - internalType: 'string', - name: '', - type: 'string', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'contract IHats', - name: 'hatsProtocol', - type: 'address', - }, - { - internalType: 'contract IERC6551Registry', - name: 'registry', - type: 'address', - }, - { - internalType: 'contract IHatsModuleFactory', - name: 'hatsModuleFactory', - type: 'address', - }, - { - internalType: 'contract ModuleProxyFactory', - name: 'moduleProxyFactory', - type: 'address', - }, - { - internalType: 'address', - name: 'decentAutonomousAdminMasterCopy', - type: 'address', - }, - { - internalType: 'address', - name: 'hatsAccountImplementation', - type: 'address', - }, - { - internalType: 'address', - name: 'keyValuePairs', - type: 'address', - }, - { - internalType: 'address', - name: 'hatsElectionEligibilityImplementation', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'wearer', - type: 'address', - }, - { - internalType: 'string', - name: 'details', - type: 'string', - }, - { - internalType: 'string', - name: 'imageURI', - type: 'string', - }, - { - components: [ - { - internalType: 'contract ISablierV2LockupLinear', - name: 'sablier', - type: 'address', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'asset', - type: 'address', - }, - { - components: [ - { - internalType: 'uint40', - name: 'start', - type: 'uint40', - }, - { - internalType: 'uint40', - name: 'cliff', - type: 'uint40', - }, - { - internalType: 'uint40', - name: 'end', - type: 'uint40', - }, - ], - internalType: 'struct LockupLinear.Timestamps', - name: 'timestamps', - type: 'tuple', - }, - { - components: [ - { - internalType: 'address', - name: 'account', - type: 'address', - }, - { - internalType: 'uint256', - name: 'fee', - type: 'uint256', - }, - ], - internalType: 'struct LockupLinear.Broker', - name: 'broker', - type: 'tuple', - }, - { - internalType: 'uint128', - name: 'totalAmount', - type: 'uint128', - }, - { - internalType: 'bool', - name: 'cancelable', - type: 'bool', - }, - { - internalType: 'bool', - name: 'transferable', - type: 'bool', - }, - ], - internalType: 'struct DecentHats_0_2_0.SablierStreamParams[]', - name: 'sablierParams', - type: 'tuple[]', - }, - { - components: [ - { - internalType: 'uint128', - name: 'termEndDateTs', - type: 'uint128', - }, - { - internalType: 'address[]', - name: 'nominatedWearers', - type: 'address[]', - }, - ], - internalType: 'struct DecentHats_0_2_0.TermedParams[]', - name: 'termedParams', - type: 'tuple[]', - }, - { - internalType: 'uint32', - name: 'maxSupply', - type: 'uint32', - }, - { - internalType: 'bool', - name: 'isMutable', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isTermed', - type: 'bool', - }, - ], - internalType: 'struct DecentHats_0_2_0.Hat', - name: 'adminHat', - type: 'tuple', - }, - { - components: [ - { - internalType: 'address', - name: 'wearer', - type: 'address', - }, - { - internalType: 'string', - name: 'details', - type: 'string', - }, - { - internalType: 'string', - name: 'imageURI', - type: 'string', - }, - { - components: [ - { - internalType: 'contract ISablierV2LockupLinear', - name: 'sablier', - type: 'address', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'asset', - type: 'address', - }, - { - components: [ - { - internalType: 'uint40', - name: 'start', - type: 'uint40', - }, - { - internalType: 'uint40', - name: 'cliff', - type: 'uint40', - }, - { - internalType: 'uint40', - name: 'end', - type: 'uint40', - }, - ], - internalType: 'struct LockupLinear.Timestamps', - name: 'timestamps', - type: 'tuple', - }, - { - components: [ - { - internalType: 'address', - name: 'account', - type: 'address', - }, - { - internalType: 'uint256', - name: 'fee', - type: 'uint256', - }, - ], - internalType: 'struct LockupLinear.Broker', - name: 'broker', - type: 'tuple', - }, - { - internalType: 'uint128', - name: 'totalAmount', - type: 'uint128', - }, - { - internalType: 'bool', - name: 'cancelable', - type: 'bool', - }, - { - internalType: 'bool', - name: 'transferable', - type: 'bool', - }, - ], - internalType: 'struct DecentHats_0_2_0.SablierStreamParams[]', - name: 'sablierParams', - type: 'tuple[]', - }, - { - components: [ - { - internalType: 'uint128', - name: 'termEndDateTs', - type: 'uint128', - }, - { - internalType: 'address[]', - name: 'nominatedWearers', - type: 'address[]', - }, - ], - internalType: 'struct DecentHats_0_2_0.TermedParams[]', - name: 'termedParams', - type: 'tuple[]', - }, - { - internalType: 'uint32', - name: 'maxSupply', - type: 'uint32', - }, - { - internalType: 'bool', - name: 'isMutable', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isTermed', - type: 'bool', - }, - ], - internalType: 'struct DecentHats_0_2_0.Hat[]', - name: 'hats', - type: 'tuple[]', - }, - { - internalType: 'string', - name: 'topHatDetails', - type: 'string', - }, - { - internalType: 'string', - name: 'topHatImageURI', - type: 'string', - }, - ], - internalType: 'struct DecentHats_0_2_0.CreateTreeParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'createAndDeclareTree', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -] as const; diff --git a/src/hooks/DAO/loaders/useHatsTree.ts b/src/hooks/DAO/loaders/useHatsTree.ts index 0c822732d0..75fb3f33b2 100644 --- a/src/hooks/DAO/loaders/useHatsTree.ts +++ b/src/hooks/DAO/loaders/useHatsTree.ts @@ -33,7 +33,6 @@ const useHatsTree = () => { hatsProtocol, erc6551Registry, hatsAccount1ofNMasterCopy: hatsAccountImplementation, - decentHatsMasterCopy, }, } = useNetworkConfig(); const publicClient = usePublicClient(); @@ -45,7 +44,6 @@ const useHatsTree = () => { hatsTreeId === undefined || hatsTreeId === null || publicClient === undefined || - decentHatsMasterCopy === undefined || contextChainId === null ) { return; @@ -61,6 +59,7 @@ const useHatsTree = () => { prettyId: true, status: true, details: true, + eligibility: true, wearers: { props: {}, }, @@ -110,7 +109,6 @@ const useHatsTree = () => { erc6551Registry, hatsAccountImplementation, publicClient, - decentHats: getAddress(decentHatsMasterCopy), }); } catch (e) { if (e instanceof DecentHatsError) { @@ -125,7 +123,6 @@ const useHatsTree = () => { erc6551Registry, hatsAccountImplementation, publicClient, - decentHats: getAddress(decentHatsMasterCopy), }); const message = 'Hats Tree ID is not valid'; toast.error(message); @@ -142,7 +139,6 @@ const useHatsTree = () => { getHatsTree(); }, [ contextChainId, - decentHatsMasterCopy, erc6551Registry, hatsAccountImplementation, hatsProtocol, diff --git a/src/store/roles/rolesStoreUtils.ts b/src/store/roles/rolesStoreUtils.ts index 6b2b37dbdb..6a717cd6db 100644 --- a/src/store/roles/rolesStoreUtils.ts +++ b/src/store/roles/rolesStoreUtils.ts @@ -1,5 +1,5 @@ import { Tree, Hat } from '@hatsprotocol/sdk-v1-subgraph'; -import { Address, Hex, PublicClient, encodePacked, getContract, keccak256 } from 'viem'; +import { Address, Hex, PublicClient, getContract } from 'viem'; import ERC6551RegistryAbi from '../../assets/abi/ERC6551RegistryAbi'; import { SablierPayment } from '../../components/pages/Roles/types'; @@ -21,7 +21,6 @@ export interface PredictAccountParams { tokenId: bigint; registryAddress: Address; publicClient: PublicClient; - decentHats: Address; } interface DecentHat { @@ -30,15 +29,19 @@ interface DecentHat { name: string; description: string; smartAddress: Address; + eligibility?: `0x${string}`; payments?: SablierPayment[]; } interface DecentTopHat extends DecentHat {} -interface DecentAdminHat extends DecentHat {} +interface DecentAdminHat extends DecentHat { + wearer?: Address; +} interface RolesStoreData { hatsTreeId: undefined | null | number; + decentHatsAddress: Address | null | undefined; hatsTree: undefined | null | DecentTree; streamsFetched: boolean; contextChainId: number | null; @@ -46,6 +49,7 @@ interface RolesStoreData { export interface DecentRoleHat extends DecentHat { wearer: Address; + eligibility?: `0x${string}`; } export interface DecentTree { @@ -66,7 +70,6 @@ export interface RolesStore extends RolesStoreData { erc6551Registry: Address; hatsAccountImplementation: Address; publicClient: PublicClient; - decentHats: Address; }) => Promise; refreshWithdrawableAmount: (hatId: Hex, streamId: string, publicClient: PublicClient) => void; updateRolesWithStreams: (updatedRolesWithStreams: DecentRoleHat[]) => void; @@ -141,26 +144,13 @@ const getHatMetadata = (hat: Hat) => { export const initialHatsStore: RolesStoreData = { hatsTreeId: undefined, hatsTree: undefined, + decentHatsAddress: undefined, streamsFetched: false, contextChainId: null, }; -export function getERC6551RegistrySalt(chainId: bigint, decentHats: Address) { - return keccak256( - encodePacked(['string', 'uint256', 'address'], ['DecentHats_0_1_0', chainId, decentHats]), - ); -} - export const predictAccountAddress = (params: PredictAccountParams) => { - const { - implementation, - chainId, - tokenContract, - tokenId, - registryAddress, - publicClient, - decentHats, - } = params; + const { implementation, chainId, tokenContract, tokenId, registryAddress, publicClient } = params; const erc6551RegistryContract = getContract({ abi: ERC6551RegistryAbi, @@ -168,11 +158,17 @@ export const predictAccountAddress = (params: PredictAccountParams) => { client: publicClient, }); - const salt = getERC6551RegistrySalt(chainId, decentHats); + /** + * @dev DO NOT CHANGE THE SALT + * @note This SALT is used to generate the account address for the Hats Smart Account + * @note This has been used in production and changing it will break the predictability of the smart account addresses + * + */ + const SALT = '0x5d0e6ce4fd951366cc55da93f6e79d8b81483109d79676a04bcc2bed6a4b5072'; return erc6551RegistryContract.read.account([ implementation, - salt, + SALT, chainId, tokenContract, tokenId, @@ -186,7 +182,6 @@ export const sanitize = async ( hats: Address, chainId: bigint, publicClient: PublicClient, - decentHats: Address, ): Promise => { if (hatsTree === undefined || hatsTree === null) { return hatsTree; @@ -206,7 +201,6 @@ export const sanitize = async ( chainId, tokenId: BigInt(rawTopHat.id), publicClient, - decentHats, }); const topHat: DecentHat = { @@ -227,15 +221,15 @@ export const sanitize = async ( chainId, tokenId: BigInt(rawAdminHat.id), publicClient, - decentHats, }); - const adminHat: DecentHat = { + const adminHat: DecentAdminHat = { id: rawAdminHat.id, prettyId: rawAdminHat.prettyId ?? '', name: adminHatMetadata.name, description: adminHatMetadata.description, smartAddress: adminHatSmartAddress, + wearer: rawAdminHat.wearers?.length ? rawAdminHat.wearers[0].id : undefined, }; const rawRoleHats = hatsTree.hats.filter(h => appearsExactlyNumberOfTimes(h.prettyId, '.', 2)); @@ -255,7 +249,6 @@ export const sanitize = async ( chainId, tokenId: BigInt(rawHat.id), publicClient, - decentHats, }); roleHats.push({ @@ -265,6 +258,7 @@ export const sanitize = async ( description: hatMetadata.description, wearer: rawHat.wearers![0].id, smartAddress: roleHatSmartAddress, + eligibility: rawHat.eligibility, }); } diff --git a/src/store/roles/useRolesStore.ts b/src/store/roles/useRolesStore.ts index 4a4dc8c13c..213bed64a2 100644 --- a/src/store/roles/useRolesStore.ts +++ b/src/store/roles/useRolesStore.ts @@ -56,7 +56,6 @@ const useRolesStore = create()((set, get) => ({ params.hatsProtocol, params.chainId, params.publicClient, - params.decentHats, ); set(() => ({ hatsTree })); }, From 86577eb126a3fd00a57c7424026684b9ccc1b3d5 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 11 Oct 2024 19:57:57 -0400 Subject: [PATCH 005/191] use zeroAddress for placeholding --- src/providers/NetworkConfig/networks/base.ts | 6 +++--- src/providers/NetworkConfig/networks/mainnet.ts | 6 +++--- src/providers/NetworkConfig/networks/optimism.ts | 6 +++--- src/providers/NetworkConfig/networks/polygon.ts | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/providers/NetworkConfig/networks/base.ts b/src/providers/NetworkConfig/networks/base.ts index 95fdd45bd8..1b4b868e87 100644 --- a/src/providers/NetworkConfig/networks/base.ts +++ b/src/providers/NetworkConfig/networks/base.ts @@ -6,7 +6,7 @@ import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from '@safe-global/safe-deployments'; -import { getAddress } from 'viem'; +import { getAddress, zeroAddress } from 'viem'; import { base } from 'wagmi/chains'; import { GovernanceType } from '../../../types'; import { NetworkConfig } from '../../../types/network'; @@ -82,8 +82,8 @@ export const baseConfig: NetworkConfig = { keyValuePairs: getAddress(a.KeyValuePairs), decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), // @todo update addresses when contracts are deployed - decentHatsV2MasterCopy: getAddress('0x0'), - decentAutonomousAdminMasterCopy: getAddress('0x0'), + decentHatsV2MasterCopy: zeroAddress, + decentAutonomousAdminMasterCopy: zeroAddress, hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/mainnet.ts b/src/providers/NetworkConfig/networks/mainnet.ts index 1363ac194d..94a81d5f68 100644 --- a/src/providers/NetworkConfig/networks/mainnet.ts +++ b/src/providers/NetworkConfig/networks/mainnet.ts @@ -5,7 +5,7 @@ import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from '@safe-global/safe-deployments'; -import { getAddress } from 'viem'; +import { getAddress, zeroAddress } from 'viem'; import { mainnet } from 'wagmi/chains'; import { GovernanceType } from '../../../types'; import { NetworkConfig } from '../../../types/network'; @@ -82,8 +82,8 @@ export const mainnetConfig: NetworkConfig = { keyValuePairs: getAddress(a.KeyValuePairs), decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), // @todo update addresses when contracts are deployed - decentHatsV2MasterCopy: getAddress('0x0'), - decentAutonomousAdminMasterCopy: getAddress('0x0'), + decentHatsV2MasterCopy: zeroAddress, + decentAutonomousAdminMasterCopy: zeroAddress, hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/optimism.ts b/src/providers/NetworkConfig/networks/optimism.ts index 863f13133c..5e311210ab 100644 --- a/src/providers/NetworkConfig/networks/optimism.ts +++ b/src/providers/NetworkConfig/networks/optimism.ts @@ -5,7 +5,7 @@ import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from '@safe-global/safe-deployments'; -import { getAddress } from 'viem'; +import { getAddress, zeroAddress } from 'viem'; import { optimism } from 'wagmi/chains'; import { GovernanceType } from '../../../types'; import { NetworkConfig } from '../../../types/network'; @@ -82,8 +82,8 @@ export const optimismConfig: NetworkConfig = { keyValuePairs: getAddress(a.KeyValuePairs), decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), // @todo update addresses when contracts are deployed - decentHatsV2MasterCopy: getAddress('0x0'), - decentAutonomousAdminMasterCopy: getAddress('0x0'), + decentHatsV2MasterCopy: zeroAddress, + decentAutonomousAdminMasterCopy: zeroAddress, hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/polygon.ts b/src/providers/NetworkConfig/networks/polygon.ts index 16d441cbf0..3963bdf883 100644 --- a/src/providers/NetworkConfig/networks/polygon.ts +++ b/src/providers/NetworkConfig/networks/polygon.ts @@ -5,7 +5,7 @@ import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from '@safe-global/safe-deployments'; -import { getAddress } from 'viem'; +import { getAddress, zeroAddress } from 'viem'; import { polygon } from 'wagmi/chains'; import { GovernanceType } from '../../../types'; import { NetworkConfig } from '../../../types/network'; @@ -82,8 +82,8 @@ export const polygonConfig: NetworkConfig = { keyValuePairs: getAddress(a.KeyValuePairs), decentHatsV1MasterCopy: getAddress(a.DecentHats_0_1_0), // @todo update addresses when contracts are deployed - decentHatsV2MasterCopy: getAddress('0x0'), - decentAutonomousAdminMasterCopy: getAddress('0x0'), + decentHatsV2MasterCopy: zeroAddress, + decentAutonomousAdminMasterCopy: zeroAddress, hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', From f04b14ea3ddddfb7ff35f34a6cb49adce6cfb973 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 11 Oct 2024 19:58:13 -0400 Subject: [PATCH 006/191] update form typing --- src/components/pages/Roles/types.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/components/pages/Roles/types.tsx b/src/components/pages/Roles/types.tsx index df82a751b0..eac5b579fb 100644 --- a/src/components/pages/Roles/types.tsx +++ b/src/components/pages/Roles/types.tsx @@ -67,24 +67,34 @@ export enum EditBadgeStatus { Updated, New, Removed, + NewTermedRole, } export const BadgeStatus: Record = { [EditBadgeStatus.Updated]: 'updated', [EditBadgeStatus.New]: 'new', [EditBadgeStatus.Removed]: 'removed', + [EditBadgeStatus.NewTermedRole]: 'newTermedRole', }; export const BadgeStatusColor: Record = { [EditBadgeStatus.Updated]: 'lilac-0', [EditBadgeStatus.New]: 'celery--2', [EditBadgeStatus.Removed]: 'red-1', + [EditBadgeStatus.NewTermedRole]: 'celery--2', }; +export interface TermedParams { + termEndDateTs: bigint; + nominatedWearers: Address[]; +} + export interface HatStruct { maxSupply: 1; // No more than this number of wearers. Hardcode to 1 details: string; // IPFS url/hash to JSON { version: '1.0', data: { name, description, ...arbitraryData } } imageURI: string; isMutable: boolean; // true wearer: Address; + isTermed: boolean; + termedParams: TermedParams[]; } export interface HatStructWithPayments extends HatStruct { @@ -123,6 +133,11 @@ export interface RoleHatFormValue // form specific state editedRole?: EditedRole; roleEditingPaymentIndex?: number; + isTermed?: boolean; + roleTerms?: { + nominee?: string; + termEndDateTs?: number; + }[]; } export interface RoleHatFormValueEdited extends RoleHatFormValue { @@ -182,3 +197,5 @@ export type PreparedEditedStreamData = PreparedNewStreamData & { roleHatSmartAddress: Address; streamContractAddress: Address; }; + +export const HATS_ADDRESS: Address = '0x0000000000000000000000000000000000004a75'; From ec6dae6a6c12d2ea97b4ca96043782f5806d54f5 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 12 Oct 2024 14:22:16 -0400 Subject: [PATCH 007/191] update to latest abi --- src/assets/abi/DecentHatsTempAbi.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/abi/DecentHatsTempAbi.ts b/src/assets/abi/DecentHatsTempAbi.ts index fbee18c969..3791eaa1dc 100644 --- a/src/assets/abi/DecentHatsTempAbi.ts +++ b/src/assets/abi/DecentHatsTempAbi.ts @@ -89,8 +89,8 @@ export const DecentHatsTempAbi = [ { "components": [ { - "internalType": "address", - "name": "sablierV2LockupLinear", + "internalType": "contract ISablierV2LockupLinear", + "name": "sablier", "type": "address" }, { @@ -219,8 +219,8 @@ export const DecentHatsTempAbi = [ { "components": [ { - "internalType": "address", - "name": "sablierV2LockupLinear", + "internalType": "contract ISablierV2LockupLinear", + "name": "sablier", "type": "address" }, { From f7f62e67a503159edcf03bd46b48514c6a2fa102 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 12 Oct 2024 14:22:25 -0400 Subject: [PATCH 008/191] term update first pass --- src/hooks/utils/useCreateRoles.ts | 363 ++++++++++++++++++++++++++++-- 1 file changed, 344 insertions(+), 19 deletions(-) diff --git a/src/hooks/utils/useCreateRoles.ts b/src/hooks/utils/useCreateRoles.ts index e4731847a0..d694f49917 100644 --- a/src/hooks/utils/useCreateRoles.ts +++ b/src/hooks/utils/useCreateRoles.ts @@ -1,25 +1,37 @@ -import { abis } from '@fractal-framework/fractal-contracts'; +import { + HatsModulesClient, + HATS_MODULES_FACTORY_ADDRESS, + HATS_MODULES_FACTORY_ABI, + checkAndEncodeArgs, +} from '@hatsprotocol/modules-sdk'; import { FormikHelpers } from 'formik'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { toast } from 'sonner'; import { Address, encodeFunctionData, getAddress, Hex, zeroAddress } from 'viem'; import { usePublicClient } from 'wagmi'; +import { DecentHatsTempAbi } from '../../assets/abi/DecentHatsTempAbi'; import ERC6551RegistryAbi from '../../assets/abi/ERC6551RegistryAbi'; import GnosisSafeL2 from '../../assets/abi/GnosisSafeL2'; import { HatsAbi } from '../../assets/abi/HatsAbi'; import HatsAccount1ofNAbi from '../../assets/abi/HatsAccount1ofN'; +import { HatsElectionsEligibilityAbi } from '../../assets/abi/HatsElectionsEligibilityAbi'; + import { EditBadgeStatus, + HATS_ADDRESS, HatStruct, HatStructWithPayments, RoleFormValues, RoleHatFormValueEdited, SablierPaymentFormValues, + TermedParams, } from '../../components/pages/Roles/types'; import { ERC6551_REGISTRY_SALT } from '../../constants/common'; import { DAO_ROUTES } from '../../constants/routes'; +import { getRandomBytes } from '../../helpers'; +import { generateSalt } from '../../models/helpers/utils'; import { useFractal } from '../../providers/App/AppProvider'; import useIPFSClient from '../../providers/App/hooks/useIPFSClient'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; @@ -41,11 +53,12 @@ export default function useCreateRoles() { chain, contracts: { hatsProtocol, - decentHatsMasterCopy, hatsAccount1ofNMasterCopy, erc6551Registry, keyValuePairs, sablierV2LockupLinear, + decentHatsMasterCopy, + zodiacModuleProxyFactory, }, } = useNetworkConfig(); @@ -58,6 +71,16 @@ export default function useCreateRoles() { const publicClient = usePublicClient(); const navigate = useNavigate(); + const hatsModulesClient = useMemo(() => { + if (!publicClient) { + return null; + } + const client = new HatsModulesClient({ + publicClient, + }); + return client; + }, [publicClient]); + const hatsDetailsBuilder = useCallback((data: { name: string; description: string }) => { return JSON.stringify({ type: '1.0', @@ -74,7 +97,13 @@ export default function useCreateRoles() { ); const createHatStruct = useCallback( - async (name: string, description: string, wearer: Address) => { + async ( + name: string, + description: string, + wearer: Address, + isTermed: boolean, + termedParams: TermedParams[], + ) => { const details = await uploadHatDescription( hatsDetailsBuilder({ name: name, @@ -88,6 +117,8 @@ export default function useCreateRoles() { imageURI: '', isMutable: true, wearer: wearer, + isTermed, + termedParams, }; return newHat; @@ -107,8 +138,10 @@ export default function useCreateRoles() { cliffTimestamp: number; endTimestamp: number; }[], + isTermed: boolean, + termedParams: TermedParams[], ) => { - const newHat = await createHatStruct(name, description, wearer); + const newHat = await createHatStruct(name, description, wearer, isTermed, termedParams); if (daoAddress === null) { throw new Error('Can not create Hat Struct (with payments) without DAO Address'); @@ -172,7 +205,6 @@ export default function useCreateRoles() { if (role.wearer === undefined) { throw new Error('Hat wearer of added hat is undefined.'); } - const sablierPayments = parseSablierPaymentsFromFormRolePayments(role.payments ?? []); return createHatStructWithPayments( @@ -180,6 +212,11 @@ export default function useCreateRoles() { role.description, getAddress(role.wearer), sablierPayments, + role.isTermed ?? false, + role.roleTerms?.map(term => ({ + termEndDateTs: term.termEndDateTs ? BigInt(term.termEndDateTs) : 0n, + nominatedWearers: term.nominee ? [getAddress(term.nominee)] : [zeroAddress], + })) ?? [], ); }), ); @@ -192,6 +229,7 @@ export default function useCreateRoles() { if (!publicClient) { throw new Error('Public client is not set'); } + return predictAccountAddress({ implementation: hatsAccount1ofNMasterCopy, chainId: BigInt(chain.id), @@ -209,18 +247,20 @@ export default function useCreateRoles() { if (!daoAddress) { throw new Error('Can not create top hat without DAO Address'); } - - const decentHatsAddress = getAddress(decentHatsMasterCopy); + // @todo remove when published to all networks + if (!decentHatsMasterCopy) { + throw new Error('Can not create top hat without DecentHatsV2MasterCopy'); + } const enableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'enableModule', - args: [decentHatsAddress], + args: [decentHatsMasterCopy], }); const disableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'disableModule', - args: [SENTINEL_MODULE, decentHatsAddress], + args: [SENTINEL_MODULE, decentHatsMasterCopy], }); const topHatDetails = await uploadHatDescription( @@ -236,19 +276,31 @@ export default function useCreateRoles() { }), ); - const adminHat: HatStructWithPayments = { + const adminHat = { maxSupply: 1, details: adminHatDetails, imageURI: '', isMutable: true, wearer: zeroAddress, sablierParams: [], + isTermed: false, + termedParams: [], }; + if (!hatsModulesClient) { + throw new Error('Cannot create Roles proposal without hatsModulesClient'); + } + await hatsModulesClient.prepare(); + // @note for now the id argument seems to be the implementation address rather than the module id + const module = hatsModulesClient.getModuleById('0xd3b916a8F0C4f9D1d5B6Af29c3C012dbd4f3149E'); + if (!module) { + throw new Error('Could not find module'); + } const addedHats = await createHatStructsForNewTreeFromRolesFormValues(modifiedHats); - const createAndDeclareTreeData = encodeFunctionData({ - abi: abis.DecentHats_0_1_0, + // @note this should be lastest version of DecentHats + // @todo replace with published abi from package + abi: DecentHatsTempAbi, functionName: 'createAndDeclareTree', args: [ { @@ -260,12 +312,17 @@ export default function useCreateRoles() { topHatImageURI: '', adminHat, hats: addedHats, + hatsModuleFactory: HATS_MODULES_FACTORY_ADDRESS, + hatsElectionEligibilityImplementation: getAddress(module.implementationAddress), + moduleProxyFactory: zodiacModuleProxyFactory, + // @note this should be lastest version of DecentHats + decentAutonomousAdminMasterCopy: decentHatsMasterCopy, }, ], }); return { - targets: [daoAddress, decentHatsAddress, daoAddress], + targets: [daoAddress, decentHatsMasterCopy, daoAddress], calldatas: [enableModuleData, createAndDeclareTreeData, disableModuleData], metaData: proposalMetadata, values: [0n, 0n, 0n], @@ -282,9 +339,65 @@ export default function useCreateRoles() { keyValuePairs, uploadHatDescription, createHatStructsForNewTreeFromRolesFormValues, + hatsModulesClient, + zodiacModuleProxyFactory, ], ); + const createEligibilityModuleTx = useCallback( + async (hatId: bigint, firstTermEnd: bigint, adminHatId: bigint) => { + if (!hatsModulesClient) { + throw new Error('Cannot create Roles proposal without hatsModulesClient'); + } + await hatsModulesClient.prepare(); + const module = hatsModulesClient.getModuleById('0xd3b916a8F0C4f9D1d5B6Af29c3C012dbd4f3149E'); + if (!module) { + throw new Error('Could not find module'); + } + + const immutableArgs = [adminHatId, 0n]; + // @todo: add args termEndDateTs + const { encodedImmutableArgs, encodedMutableArgs } = checkAndEncodeArgs({ + module, + immutableArgs, + mutableArgs: [firstTermEnd], + }); + + // @todo should this salt generation be the same as in DecentHats Contract? + const salt = BigInt(generateSalt(encodedMutableArgs, getRandomBytes())); + const createElectionEligibilityInstanceTx = { + calldata: encodeFunctionData({ + abi: HATS_MODULES_FACTORY_ABI, + functionName: 'createHatsModule', + args: [ + getAddress(module.implementationAddress), + BigInt(hatId), + encodedImmutableArgs, + encodedMutableArgs, + salt, + ], + }), + }; + const predictedElectionEligibilityInstance = await hatsModulesClient.predictHatsModuleAddress( + { + moduleId: getAddress(module.id), + hatId: hatId, + immutableArgs: immutableArgs, + saltNonce: salt, + }, + ); + + return { + electionDeployModuleTx: { + calldata: createElectionEligibilityInstanceTx.calldata, + targetAddress: HATS_MODULES_FACTORY_ADDRESS, + }, + predictedElectionEligibilityInstance: predictedElectionEligibilityInstance, + }; + }, + [hatsModulesClient], + ); + const createNewHatTx = useCallback( async (formRole: RoleHatFormValueEdited, adminHatId: bigint, topHatSmartAccount: Address) => { if (formRole.name === undefined || formRole.description === undefined) { @@ -299,6 +412,8 @@ export default function useCreateRoles() { formRole.name, formRole.description, getAddress(formRole.wearer), + false, + [], ); return { @@ -321,6 +436,92 @@ export default function useCreateRoles() { }, [createHatStruct, hatsProtocol], ); + const createNewTermedHatTxs = useCallback( + async (formRole: RoleHatFormValueEdited, adminHatId: bigint) => { + if (formRole.name === undefined || formRole.description === undefined) { + throw new Error('Name or description of added Role is undefined.'); + } + + if (formRole.wearer === undefined) { + throw new Error('Member of added Role is undefined.'); + } + if (formRole.roleTerms?.[0].termEndDateTs === undefined) { + throw new Error('Term end date of added Role is undefined.'); + } + if (formRole.roleTerms?.[0].nominee === undefined) { + throw new Error('Nominee of added Role is undefined.'); + } + + let firstWearer = getAddress(formRole.wearer); + let txData: { calldata: Hex; targetAddress: Address }[] = []; + let eligibilityModule = HATS_ADDRESS; + + const { electionDeployModuleTx, predictedElectionEligibilityInstance } = + await createEligibilityModuleTx( + BigInt(formRole.id), + BigInt(formRole.roleTerms[0].termEndDateTs), + adminHatId, + ); + txData.push(electionDeployModuleTx); + eligibilityModule = predictedElectionEligibilityInstance; + firstWearer = getAddress(formRole.roleTerms[0].nominee); + + const hatStruct = await createHatStruct( + formRole.name, + formRole.description, + getAddress(firstWearer), + true, + [ + { + termEndDateTs: BigInt(formRole.roleTerms[0].termEndDateTs), + nominatedWearers: [getAddress(formRole.roleTerms[0].nominee)], + }, + ], + ); + + txData.push({ + calldata: encodeFunctionData({ + abi: HatsAbi, + functionName: 'createHat', + args: [ + adminHatId, // adminHatId + hatStruct.details, // details + hatStruct.maxSupply, // maxSupply + HATS_ADDRESS, // toggleModule + eligibilityModule, // eligibilityModule + !formRole.isTermed ? hatStruct.isMutable : false, // isMutable + hatStruct.wearer, // wearer + ], + }), + targetAddress: hatsProtocol, + }); + if (eligibilityModule !== HATS_ADDRESS) { + if (formRole.roleTerms?.[0].termEndDateTs === undefined) { + throw new Error('Term end date of added Role is undefined.'); + } + // create transactions to start first term right away + txData.push({ + calldata: encodeFunctionData({ + abi: HatsElectionsEligibilityAbi, + functionName: 'elect', + args: [BigInt(formRole.roleTerms[0].termEndDateTs), [hatStruct.wearer]], + }), + targetAddress: eligibilityModule, + }); + txData.push({ + calldata: encodeFunctionData({ + abi: HatsElectionsEligibilityAbi, + functionName: 'startNextTerm', + args: [], + }), + targetAddress: eligibilityModule, + }); + } + + return txData; + }, + [createHatStruct, hatsProtocol, createEligibilityModuleTx], + ); const mintHatTx = useCallback( (newHatId: bigint, formHat: RoleHatFormValueEdited) => { @@ -420,6 +621,10 @@ export default function useCreateRoles() { throw new Error('Cannot prepare transactions without hats tree or DAO address'); } + if (!publicClient) { + throw new Error('Cannot prepare transactions without public client'); + } + const topHatAccount = hatsTree.topHat.smartAddress; const adminHatId = BigInt(hatsTree.adminHat.id); @@ -476,11 +681,15 @@ export default function useCreateRoles() { hatsCount: hatsTree.roleHatsTotalCount + newHatCount, }); newHatCount++; - - allTxs.push(await createNewHatTx(formHat, adminHatId, topHatAccount)); + if (formHat.isTermed) { + allTxs.push(...(await createNewTermedHatTxs(formHat, adminHatId))); + } else { + allTxs.push(await createNewHatTx(formHat, adminHatId, topHatAccount)); + } allTxs.push(mintHatTx(newHatId, formHat)); allTxs.push(createSmartAccountTx(BigInt(newHatId))); + // if there are streams to create const newStreams = getNewStreamsFromFormHat(formHat); if (newStreams.length > 0) { @@ -586,7 +795,7 @@ export default function useCreateRoles() { targetAddress: hatsProtocol, }); } - if (formHat.editedRole.fieldNames.includes('member')) { + if (formHat.editedRole.fieldNames.includes('member') && !formHat.isTermed) { const newWearer = getAddress(formHat.wearer); if (formHat.smartAddress === undefined) { throw new Error('Cannot prepare transactions for edited role without smart address'); @@ -650,8 +859,7 @@ export default function useCreateRoles() { }); } } - - if (formHat.editedRole.fieldNames.includes('payments')) { + if (formHat.editedRole.fieldNames.includes('payments') && !formHat.isTermed) { const cancelledStreamsOnHat = getCancelledStreamsFromFormHat(formHat); if (cancelledStreamsOnHat.length) { // This role edit includes stream cancels. In case there are any unclaimed funds on these streams, @@ -723,6 +931,121 @@ export default function useCreateRoles() { allTxs.push(...newStreamTxData.preparedStreamCreationTransactions); } } + if (formHat.editedRole.fieldNames.includes('term')) { + if (formHat.isTermed) { + // @note {assumption}: We are only dealing with the next term here + const latestTerm = formHat.roleTerms?.pop(); + + if (!latestTerm) { + throw new Error('No term data found'); + } + if (latestTerm.termEndDateTs === undefined) { + throw new Error('Term end date of added Role is undefined.'); + } + if (latestTerm.nominee === undefined) { + throw new Error('Nominee of added Role is undefined.'); + } + // @note {assumption}: We have already determined the eligibility address is the election module + // @todo double check assumption + if (formHat.eligibility === undefined) { + throw new Error( + 'Cannot prepare transactions for edited role without eligibility address', + ); + } + if (formHat.smartAddress === undefined) { + throw new Error( + 'Cannot prepare transactions for edited role without smart address', + ); + } + const originalHat = getHat(formHat.id); + if (!originalHat) { + throw new Error('Cannot find original hat'); + } + + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsElectionsEligibilityAbi, + functionName: 'setNextTerm', + args: [BigInt(latestTerm.termEndDateTs)], + }), + targetAddress: formHat.eligibility, + }); + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsElectionsEligibilityAbi, + functionName: 'elect', + args: [BigInt(latestTerm.termEndDateTs), [getAddress(latestTerm.nominee)]], + }), + targetAddress: formHat.eligibility, + }); + + // @note {assumption at proposal creation}: previous term is on going + const previousTerm = formHat.roleTerms?.[formHat.roleTerms.length - 2]; + if (previousTerm?.termEndDateTs ?? 0 < Date.now()) { + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsElectionsEligibilityAbi, + functionName: 'startNextTerm', + args: [], + }), + targetAddress: formHat.eligibility, + }); + // flush funds from previous term + // @note {assumption}: no stream should need to be cancelled if past previous term + const streamsWithFundsToClaim = getStreamsWithFundsToClaimFromFromHat(formHat); + if (streamsWithFundsToClaim.length) { + for (const stream of streamsWithFundsToClaim) { + if (!stream.streamId || !stream.contractAddress) { + throw new Error( + 'Stream ID and Stream ContractAddress is required for flush stream transaction', + ); + } + // transfer hat to DAO + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsAbi, + functionName: 'transferHat', + args: [BigInt(formHat.id), getAddress(formHat.wearer), daoAddress], + }), + targetAddress: hatsProtocol, + }); + const flushStreamTxCalldata = prepareFlushStreamTxs({ + streamId: stream.streamId, + to: originalHat.wearer, + smartAccount: formHat.smartAddress, + }); + + allTxs.push(...flushStreamTxCalldata); + } + } + if (streamsWithFundsToClaim.length) { + // transfer hat to nominee from DAO + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsAbi, + functionName: 'transferHat', + args: [BigInt(formHat.id), daoAddress, getAddress(latestTerm.nominee)], + }), + targetAddress: hatsProtocol, + }); + } else { + // transfer hat to nominee from wearer + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsAbi, + functionName: 'transferHat', + args: [ + BigInt(formHat.id), + getAddress(formHat.wearer), + getAddress(latestTerm.nominee), + ], + }), + targetAddress: hatsProtocol, + }); + } + } + } + } } else { throw new Error('Invalid Edited Status'); } @@ -738,6 +1061,7 @@ export default function useCreateRoles() { [ createBatchLinearStreamCreationTx, createNewHatTx, + createNewTermedHatTxs, createSmartAccountTx, daoAddress, getActiveStreamsFromFormHat, @@ -754,6 +1078,7 @@ export default function useCreateRoles() { prepareCancelStreamTxs, prepareFlushStreamTxs, uploadHatDescription, + publicClient, ], ); From 045f322e2e57fcbe070485224bf27979db2b55b7 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 12 Oct 2024 21:16:30 -0400 Subject: [PATCH 009/191] revert change to vite version --- package-lock.json | 204 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 103 insertions(+), 103 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6955412d5b..88cf6ec4c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "remark-gfm": "^4.0.0", "sonner": "^1.5.0", "viem": "^2.13.1", - "vite": "5.1.0", + "vite": "5.3.4", "vite-plugin-checker": "^0.6.4", "wagmi": "^2.12.12", "yup": "^1.4.0", @@ -3701,9 +3701,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -3717,9 +3717,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -3733,9 +3733,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -3749,9 +3749,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -3765,9 +3765,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -3781,9 +3781,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -3797,9 +3797,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -3813,9 +3813,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -3829,9 +3829,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -3845,9 +3845,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -3861,9 +3861,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -3877,9 +3877,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -3893,9 +3893,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -3909,9 +3909,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -3925,9 +3925,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -3941,9 +3941,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -3957,9 +3957,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -3973,9 +3973,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -3989,9 +3989,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -4005,9 +4005,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -4021,9 +4021,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -4037,9 +4037,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -4053,9 +4053,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -15200,9 +15200,9 @@ } }, "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -15212,29 +15212,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -42505,14 +42505,14 @@ } }, "node_modules/vite": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.0.tgz", - "integrity": "sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.4.tgz", + "integrity": "sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==", "license": "MIT", "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.39", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" diff --git a/package.json b/package.json index 2e3a1669c3..985ef9a39a 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "remark-gfm": "^4.0.0", "sonner": "^1.5.0", "viem": "^2.13.1", - "vite": "5.1.0", + "vite": "5.3.4", "vite-plugin-checker": "^0.6.4", "wagmi": "^2.12.12", "yup": "^1.4.0", From a0aa0f3e9bcbef47dfc9742f7613aefa2471f757 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:41:28 -0400 Subject: [PATCH 010/191] run pretty --- .../abi/DecentAutonomousAdminTempAbi.ts | 116 ++--- src/assets/abi/DecentHatsTempAbi.ts | 448 +++++++++--------- .../NetworkConfig/networks/sepolia.ts | 2 +- 3 files changed, 283 insertions(+), 283 deletions(-) diff --git a/src/assets/abi/DecentAutonomousAdminTempAbi.ts b/src/assets/abi/DecentAutonomousAdminTempAbi.ts index c53738d0d1..14cde76424 100644 --- a/src/assets/abi/DecentAutonomousAdminTempAbi.ts +++ b/src/assets/abi/DecentAutonomousAdminTempAbi.ts @@ -1,87 +1,87 @@ export default [ { - "inputs": [], - "name": "NAME", - "outputs": [ + inputs: [], + name: 'NAME', + outputs: [ { - "internalType": "string", - "name": "", - "type": "string" - } + internalType: 'string', + name: '', + type: 'string', + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: 'view', + type: 'function', }, { - "inputs": [], - "name": "setUp", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + inputs: [], + name: 'setUp', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', }, { - "inputs": [ + inputs: [ { - "components": [ + components: [ { - "internalType": "address", - "name": "currentWearer", - "type": "address" + internalType: 'address', + name: 'currentWearer', + type: 'address', }, { - "internalType": "contract IHats", - "name": "userHatProtocol", - "type": "address" + internalType: 'contract IHats', + name: 'userHatProtocol', + type: 'address', }, { - "internalType": "uint256", - "name": "userHatId", - "type": "uint256" + internalType: 'uint256', + name: 'userHatId', + type: 'uint256', }, { - "internalType": "address", - "name": "nominatedWearer", - "type": "address" + internalType: 'address', + name: 'nominatedWearer', + type: 'address', }, { - "components": [ + components: [ { - "internalType": "uint256", - "name": "streamId", - "type": "uint256" + internalType: 'uint256', + name: 'streamId', + type: 'uint256', }, { - "internalType": "contract ISablierV2LockupLinear", - "name": "sablierV2LockupLinear", - "type": "address" - } + internalType: 'contract ISablierV2LockupLinear', + name: 'sablierV2LockupLinear', + type: 'address', + }, ], - "internalType": "struct DecentAutonomousAdmin.SablierStreamInfo[]", - "name": "sablierStreamInfo", - "type": "tuple[]" - } + internalType: 'struct DecentAutonomousAdmin.SablierStreamInfo[]', + name: 'sablierStreamInfo', + type: 'tuple[]', + }, ], - "internalType": "struct DecentAutonomousAdmin.TriggerStartArgs", - "name": "args", - "type": "tuple" - } + internalType: 'struct DecentAutonomousAdmin.TriggerStartArgs', + name: 'args', + type: 'tuple', + }, ], - "name": "triggerStartNextTerm", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + name: 'triggerStartNextTerm', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', }, { - "inputs": [], - "name": "version_", - "outputs": [ + inputs: [], + name: 'version_', + outputs: [ { - "internalType": "string", - "name": "", - "type": "string" - } + internalType: 'string', + name: '', + type: 'string', + }, ], - "stateMutability": "view", - "type": "function" - } + stateMutability: 'view', + type: 'function', + }, ] as const; diff --git a/src/assets/abi/DecentHatsTempAbi.ts b/src/assets/abi/DecentHatsTempAbi.ts index 3791eaa1dc..33329bb634 100644 --- a/src/assets/abi/DecentHatsTempAbi.ts +++ b/src/assets/abi/DecentHatsTempAbi.ts @@ -1,353 +1,353 @@ export const DecentHatsTempAbi = [ { - "inputs": [], - "name": "NAME", - "outputs": [ + inputs: [], + name: 'NAME', + outputs: [ { - "internalType": "string", - "name": "", - "type": "string" - } + internalType: 'string', + name: '', + type: 'string', + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: 'view', + type: 'function', }, { - "inputs": [], - "name": "SALT", - "outputs": [ + inputs: [], + name: 'SALT', + outputs: [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: 'view', + type: 'function', }, { - "inputs": [ + inputs: [ { - "components": [ + components: [ { - "internalType": "contract IHats", - "name": "hatsProtocol", - "type": "address" + internalType: 'contract IHats', + name: 'hatsProtocol', + type: 'address', }, { - "internalType": "contract IERC6551Registry", - "name": "registry", - "type": "address" + internalType: 'contract IERC6551Registry', + name: 'registry', + type: 'address', }, { - "internalType": "contract IHatsModuleFactory", - "name": "hatsModuleFactory", - "type": "address" + internalType: 'contract IHatsModuleFactory', + name: 'hatsModuleFactory', + type: 'address', }, { - "internalType": "contract ModuleProxyFactory", - "name": "moduleProxyFactory", - "type": "address" + internalType: 'contract ModuleProxyFactory', + name: 'moduleProxyFactory', + type: 'address', }, { - "internalType": "address", - "name": "decentAutonomousAdminMasterCopy", - "type": "address" + internalType: 'address', + name: 'decentAutonomousAdminMasterCopy', + type: 'address', }, { - "internalType": "address", - "name": "hatsAccountImplementation", - "type": "address" + internalType: 'address', + name: 'hatsAccountImplementation', + type: 'address', }, { - "internalType": "address", - "name": "keyValuePairs", - "type": "address" + internalType: 'address', + name: 'keyValuePairs', + type: 'address', }, { - "internalType": "address", - "name": "hatsElectionEligibilityImplementation", - "type": "address" + internalType: 'address', + name: 'hatsElectionEligibilityImplementation', + type: 'address', }, { - "components": [ + components: [ { - "internalType": "address", - "name": "wearer", - "type": "address" + internalType: 'address', + name: 'wearer', + type: 'address', }, { - "internalType": "string", - "name": "details", - "type": "string" + internalType: 'string', + name: 'details', + type: 'string', }, { - "internalType": "string", - "name": "imageURI", - "type": "string" + internalType: 'string', + name: 'imageURI', + type: 'string', }, { - "components": [ + components: [ { - "internalType": "contract ISablierV2LockupLinear", - "name": "sablier", - "type": "address" + internalType: 'contract ISablierV2LockupLinear', + name: 'sablier', + type: 'address', }, { - "internalType": "address", - "name": "sender", - "type": "address" + internalType: 'address', + name: 'sender', + type: 'address', }, { - "internalType": "address", - "name": "asset", - "type": "address" + internalType: 'address', + name: 'asset', + type: 'address', }, { - "components": [ + components: [ { - "internalType": "uint40", - "name": "start", - "type": "uint40" + internalType: 'uint40', + name: 'start', + type: 'uint40', }, { - "internalType": "uint40", - "name": "cliff", - "type": "uint40" + internalType: 'uint40', + name: 'cliff', + type: 'uint40', }, { - "internalType": "uint40", - "name": "end", - "type": "uint40" - } + internalType: 'uint40', + name: 'end', + type: 'uint40', + }, ], - "internalType": "struct LockupLinear.Timestamps", - "name": "timestamps", - "type": "tuple" + internalType: 'struct LockupLinear.Timestamps', + name: 'timestamps', + type: 'tuple', }, { - "components": [ + components: [ { - "internalType": "address", - "name": "account", - "type": "address" + internalType: 'address', + name: 'account', + type: 'address', }, { - "internalType": "UD60x18", - "name": "fee", - "type": "uint256" - } + internalType: 'UD60x18', + name: 'fee', + type: 'uint256', + }, ], - "internalType": "struct Broker", - "name": "broker", - "type": "tuple" + internalType: 'struct Broker', + name: 'broker', + type: 'tuple', }, { - "internalType": "uint128", - "name": "totalAmount", - "type": "uint128" + internalType: 'uint128', + name: 'totalAmount', + type: 'uint128', }, { - "internalType": "bool", - "name": "cancelable", - "type": "bool" + internalType: 'bool', + name: 'cancelable', + type: 'bool', }, { - "internalType": "bool", - "name": "transferable", - "type": "bool" - } + internalType: 'bool', + name: 'transferable', + type: 'bool', + }, ], - "internalType": "struct DecentHats.SablierStreamParams[]", - "name": "sablierParams", - "type": "tuple[]" + internalType: 'struct DecentHats.SablierStreamParams[]', + name: 'sablierParams', + type: 'tuple[]', }, { - "components": [ + components: [ { - "internalType": "uint128", - "name": "termEndDateTs", - "type": "uint128" + internalType: 'uint128', + name: 'termEndDateTs', + type: 'uint128', }, { - "internalType": "address[]", - "name": "nominatedWearers", - "type": "address[]" - } + internalType: 'address[]', + name: 'nominatedWearers', + type: 'address[]', + }, ], - "internalType": "struct DecentHats.TermedParams[]", - "name": "termedParams", - "type": "tuple[]" + internalType: 'struct DecentHats.TermedParams[]', + name: 'termedParams', + type: 'tuple[]', }, { - "internalType": "uint32", - "name": "maxSupply", - "type": "uint32" + internalType: 'uint32', + name: 'maxSupply', + type: 'uint32', }, { - "internalType": "bool", - "name": "isMutable", - "type": "bool" + internalType: 'bool', + name: 'isMutable', + type: 'bool', }, { - "internalType": "bool", - "name": "isTermed", - "type": "bool" - } + internalType: 'bool', + name: 'isTermed', + type: 'bool', + }, ], - "internalType": "struct DecentHats.Hat", - "name": "adminHat", - "type": "tuple" + internalType: 'struct DecentHats.Hat', + name: 'adminHat', + type: 'tuple', }, { - "components": [ + components: [ { - "internalType": "address", - "name": "wearer", - "type": "address" + internalType: 'address', + name: 'wearer', + type: 'address', }, { - "internalType": "string", - "name": "details", - "type": "string" + internalType: 'string', + name: 'details', + type: 'string', }, { - "internalType": "string", - "name": "imageURI", - "type": "string" + internalType: 'string', + name: 'imageURI', + type: 'string', }, { - "components": [ + components: [ { - "internalType": "contract ISablierV2LockupLinear", - "name": "sablier", - "type": "address" + internalType: 'contract ISablierV2LockupLinear', + name: 'sablier', + type: 'address', }, { - "internalType": "address", - "name": "sender", - "type": "address" + internalType: 'address', + name: 'sender', + type: 'address', }, { - "internalType": "address", - "name": "asset", - "type": "address" + internalType: 'address', + name: 'asset', + type: 'address', }, { - "components": [ + components: [ { - "internalType": "uint40", - "name": "start", - "type": "uint40" + internalType: 'uint40', + name: 'start', + type: 'uint40', }, { - "internalType": "uint40", - "name": "cliff", - "type": "uint40" + internalType: 'uint40', + name: 'cliff', + type: 'uint40', }, { - "internalType": "uint40", - "name": "end", - "type": "uint40" - } + internalType: 'uint40', + name: 'end', + type: 'uint40', + }, ], - "internalType": "struct LockupLinear.Timestamps", - "name": "timestamps", - "type": "tuple" + internalType: 'struct LockupLinear.Timestamps', + name: 'timestamps', + type: 'tuple', }, { - "components": [ + components: [ { - "internalType": "address", - "name": "account", - "type": "address" + internalType: 'address', + name: 'account', + type: 'address', }, { - "internalType": "UD60x18", - "name": "fee", - "type": "uint256" - } + internalType: 'UD60x18', + name: 'fee', + type: 'uint256', + }, ], - "internalType": "struct Broker", - "name": "broker", - "type": "tuple" + internalType: 'struct Broker', + name: 'broker', + type: 'tuple', }, { - "internalType": "uint128", - "name": "totalAmount", - "type": "uint128" + internalType: 'uint128', + name: 'totalAmount', + type: 'uint128', }, { - "internalType": "bool", - "name": "cancelable", - "type": "bool" + internalType: 'bool', + name: 'cancelable', + type: 'bool', }, { - "internalType": "bool", - "name": "transferable", - "type": "bool" - } + internalType: 'bool', + name: 'transferable', + type: 'bool', + }, ], - "internalType": "struct DecentHats.SablierStreamParams[]", - "name": "sablierParams", - "type": "tuple[]" + internalType: 'struct DecentHats.SablierStreamParams[]', + name: 'sablierParams', + type: 'tuple[]', }, { - "components": [ + components: [ { - "internalType": "uint128", - "name": "termEndDateTs", - "type": "uint128" + internalType: 'uint128', + name: 'termEndDateTs', + type: 'uint128', }, { - "internalType": "address[]", - "name": "nominatedWearers", - "type": "address[]" - } + internalType: 'address[]', + name: 'nominatedWearers', + type: 'address[]', + }, ], - "internalType": "struct DecentHats.TermedParams[]", - "name": "termedParams", - "type": "tuple[]" + internalType: 'struct DecentHats.TermedParams[]', + name: 'termedParams', + type: 'tuple[]', }, { - "internalType": "uint32", - "name": "maxSupply", - "type": "uint32" + internalType: 'uint32', + name: 'maxSupply', + type: 'uint32', }, { - "internalType": "bool", - "name": "isMutable", - "type": "bool" + internalType: 'bool', + name: 'isMutable', + type: 'bool', }, { - "internalType": "bool", - "name": "isTermed", - "type": "bool" - } + internalType: 'bool', + name: 'isTermed', + type: 'bool', + }, ], - "internalType": "struct DecentHats.Hat[]", - "name": "hats", - "type": "tuple[]" + internalType: 'struct DecentHats.Hat[]', + name: 'hats', + type: 'tuple[]', }, { - "internalType": "string", - "name": "topHatDetails", - "type": "string" + internalType: 'string', + name: 'topHatDetails', + type: 'string', }, { - "internalType": "string", - "name": "topHatImageURI", - "type": "string" - } + internalType: 'string', + name: 'topHatImageURI', + type: 'string', + }, ], - "internalType": "struct DecentHats.CreateTreeParams", - "name": "params", - "type": "tuple" - } + internalType: 'struct DecentHats.CreateTreeParams', + name: 'params', + type: 'tuple', + }, ], - "name": "createAndDeclareTree", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } + name: 'createAndDeclareTree', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, ] as const; diff --git a/src/providers/NetworkConfig/networks/sepolia.ts b/src/providers/NetworkConfig/networks/sepolia.ts index e5969a003c..992238624e 100644 --- a/src/providers/NetworkConfig/networks/sepolia.ts +++ b/src/providers/NetworkConfig/networks/sepolia.ts @@ -81,7 +81,7 @@ export const sepoliaConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), decentHatsMasterCopy: getAddress('0xaFdD339cE4Ed6638a5fba3147a2F0e4EF6d5f67a'), - decentAutonomousAdminMasterCopy: getAddress('0xd8784CEeC9cbA6c7eF31849Dd2c708c2AFc37b36'), + decentAutonomousAdminMasterCopy: getAddress('0xd8784CEeC9cbA6c7eF31849Dd2c708c2AFc37b36'), decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', From 0d350159e5c4e166dfd6845eabd542f00ede16db Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Tue, 15 Oct 2024 07:37:38 -0400 Subject: [PATCH 011/191] update role form to include term toggle - adds member panel - adds term toggle - updates roles translation --- .../components/button/button.variants.ts | 15 + .../pages/Roles/forms/RoleFormInfo.tsx | 28 -- .../pages/Roles/forms/RoleFormMember.tsx | 298 ++++++++++++++++++ .../pages/Roles/forms/RoleFormTabs.tsx | 34 ++ src/i18n/locales/en/common.json | 5 +- src/i18n/locales/en/roles.json | 10 +- 6 files changed, 358 insertions(+), 32 deletions(-) create mode 100644 src/components/pages/Roles/forms/RoleFormMember.tsx diff --git a/src/assets/theme/components/button/button.variants.ts b/src/assets/theme/components/button/button.variants.ts index 6be8be51d3..95c04a7255 100644 --- a/src/assets/theme/components/button/button.variants.ts +++ b/src/assets/theme/components/button/button.variants.ts @@ -45,6 +45,20 @@ const secondary = defineStyle({ }, }); +const secondaryRed = defineStyle({ + border: '1px solid', + borderColor: 'red-1', + color: 'red-1', + _hover: { + borderColor: 'red-0', + color: 'red-0', + }, + _active: { + borderColor: 'red-0', + color: 'red-0', + }, +}); + const tertiaryDisabled = { color: 'neutral-5', }; @@ -96,6 +110,7 @@ const stepper = defineStyle({ const buttonVariants = { primary, secondary, + secondaryRed, tertiary, stepper, }; diff --git a/src/components/pages/Roles/forms/RoleFormInfo.tsx b/src/components/pages/Roles/forms/RoleFormInfo.tsx index 2ceb812f0f..59c4904c47 100644 --- a/src/components/pages/Roles/forms/RoleFormInfo.tsx +++ b/src/components/pages/Roles/forms/RoleFormInfo.tsx @@ -2,9 +2,7 @@ import { Box, FormControl } from '@chakra-ui/react'; import { Field, FieldProps } from 'formik'; import { useTranslation } from 'react-i18next'; import { DETAILS_BOX_SHADOW } from '../../../../constants/common'; -import { AddressInput } from '../../../ui/forms/EthAddressInput'; import { InputComponent, TextareaComponent } from '../../../ui/forms/InputComponent'; -import LabelWrapper from '../../../ui/forms/LabelWrapper'; import { RoleFormValues } from '../types'; export default function RoleFormInfo() { @@ -84,32 +82,6 @@ export default function RoleFormInfo() { )} - - - {({ - field, - form: { setFieldValue, setFieldTouched }, - meta, - }: FieldProps) => ( - - { - setFieldTouched(field.name, true); - }} - onChange={e => { - setFieldValue(field.name, e.target.value); - }} - /> - - )} - - ); } diff --git a/src/components/pages/Roles/forms/RoleFormMember.tsx b/src/components/pages/Roles/forms/RoleFormMember.tsx new file mode 100644 index 0000000000..017babf6b1 --- /dev/null +++ b/src/components/pages/Roles/forms/RoleFormMember.tsx @@ -0,0 +1,298 @@ +import { + Box, + Button, + Flex, + FormControl, + Hide, + Icon, + Switch, + Text, + useDisclosure, +} from '@chakra-ui/react'; +import { + ArrowLineLeft, + CalendarX, + ClockCountdown, + FileX, + WarningDiamond, +} from '@phosphor-icons/react'; +import { Field, FieldProps } from 'formik'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DETAILS_BOX_SHADOW } from '../../../../constants/common'; +import DraggableDrawer from '../../../ui/containers/DraggableDrawer'; +import { AddressInput } from '../../../ui/forms/EthAddressInput'; +import LabelWrapper from '../../../ui/forms/LabelWrapper'; +import { ModalBase } from '../../../ui/modals/ModalBase'; +import { RoleFormValues } from '../types'; + +function RoleMemberWearerInput() { + const { t } = useTranslation('roles'); + return ( + + + {({ + field, + form: { setFieldValue, setFieldTouched }, + meta, + }: FieldProps) => ( + + { + setFieldTouched(field.name, true); + }} + onChange={e => { + setFieldValue(field.name, e.target.value); + }} + /> + + )} + + + ); +} + +function RoleMemberConfirmationScreen({ + onConfirmClick, + onCancelClick, +}: { + onConfirmClick: () => void; + onCancelClick: () => void; +}) { + const { t } = useTranslation(['roles', 'common']); + return ( + + + + + {t('addTermLengthTitle')} + + + + + {t('addTermConfirmationStatementDate')} + + + + {t('addTermConfirmationStatementPayment')} + + + + {t('addTermConfirmationStatementImmutable')} + + + + + + + + + ); +} + +function RoleMemberConfirmationPortal({ + onConfirmClick, + onCancelClick, + isOpen, + onOpen, + onClose, +}: { + onConfirmClick: () => void; + onCancelClick: () => void; + isOpen: boolean; + onOpen: () => void; + onClose: () => void; +}) { + return ( + <> + + + + + + + {}} + isSearchInputModal={false} + > + + + + + ); +} + +function RoleFormMemberTermToggle() { + const { t } = useTranslation('roles'); + const [seenConfirmation, setSeenConfirmation] = useState(false); + const { isOpen, onOpen, onClose } = useDisclosure(); + + return ( + + + {({ field, form: { setFieldValue } }: FieldProps) => ( + <> + + + + {t('addTermLengths')} + + + + {t('addTermLengthSubTitle')} + + + + { + if (!seenConfirmation) { + setFieldValue(field.name, false); + onOpen(); + } else { + field.onChange(e); + } + }} + isChecked={field.value} + /> + + + { + setSeenConfirmation(true); + setFieldValue(field.name, true); + onClose(); + }} + onCancelClick={() => { + onClose(); + }} + isOpen={isOpen} + onOpen={onOpen} + onClose={onClose} + /> + + )} + + + ); +} + +export default function RoleFormMember() { + return ( + <> + + + + + + ); +} diff --git a/src/components/pages/Roles/forms/RoleFormTabs.tsx b/src/components/pages/Roles/forms/RoleFormTabs.tsx index 6a47828b19..d93cde363f 100644 --- a/src/components/pages/Roles/forms/RoleFormTabs.tsx +++ b/src/components/pages/Roles/forms/RoleFormTabs.tsx @@ -10,6 +10,7 @@ import { useNetworkConfig } from '../../../../providers/NetworkConfig/NetworkCon import { useRolesStore } from '../../../../store/roles'; import { EditBadgeStatus, RoleFormValues, RoleHatFormValue } from '../types'; import RoleFormInfo from './RoleFormInfo'; +import RoleFormMember from './RoleFormMember'; import RoleFormPaymentStream from './RoleFormPaymentStream'; import { RoleFormPaymentStreams } from './RoleFormPaymentStreams'; import { useRoleFormEditedRole } from './useRoleFormEditedRole'; @@ -63,15 +64,48 @@ export default function RoleFormTabs({ return ( <> + {/* */} {t('roleInfo')} + {t('member')} {t('payments')} + + + diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 4b4bc585a7..7dd8a42ac6 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -115,5 +115,6 @@ "goTo": "Go to", "none": "None", "ipfsLoadingErrorMessage": "Error fetching data from IPFS, please try again later.", - "ipfsSavingErrorMessage": "Error saving data to IPFS, please try again later." -} + "ipfsSavingErrorMessage": "Error saving data to IPFS, please try again later.", + "confirm": "Confirm" +} \ No newline at end of file diff --git a/src/i18n/locales/en/roles.json b/src/i18n/locales/en/roles.json index 55ba79ea51..be9cb7d4f9 100644 --- a/src/i18n/locales/en/roles.json +++ b/src/i18n/locales/en/roles.json @@ -91,5 +91,11 @@ "cancelPaymentInfoMessage": "These values can’t be edited. To update them, please cancel this payment and create a new one.", "cancellingPaymentInfoMessage": "This payment is marked for cancelling and thus can not be edited.", "confirmCancelPaymentTitle": "Are you sure you want to cancel this payment?", - "confirmCancelPaymentBody": "This action cannot be undone." -} + "confirmCancelPaymentBody": "This action cannot be undone.", + "addTermLengths": "Add Term Lengths", + "addTermLengthSubTitle": "This action will permanently add term elections to this role.", + "addTermLengthTitle": "Add a term length to this role?", + "addTermConfirmationStatementDate": "Term role has a set expiration date.", + "addTermConfirmationStatementPayment": "Current Payments tied to the role will be deleted.", + "addTermConfirmationStatementImmutable": "Once set, the role cannot be converted back to unlimited." +} \ No newline at end of file From 0efae266f0a50e0eaac4e976b28f8878c8acfe0b Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Tue, 15 Oct 2024 23:31:06 -0400 Subject: [PATCH 012/191] fix tab word wrapping --- src/assets/theme/components/tabs/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/assets/theme/components/tabs/index.ts b/src/assets/theme/components/tabs/index.ts index c5352673ef..f3070c085a 100644 --- a/src/assets/theme/components/tabs/index.ts +++ b/src/assets/theme/components/tabs/index.ts @@ -19,6 +19,7 @@ const twoToneVariant = definePartsStyle({ padding: '0.5rem 1rem', width: { base: 'full', md: 'fit-content' }, borderRadius: '0.25rem', + whiteSpace: 'nowrap', color: 'neutral-6', _selected: { background: 'neutral-2', From 460db487b8bc83d144eafb2dc1db45f0e2901088 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 17 Oct 2024 02:59:02 -0400 Subject: [PATCH 013/191] adds more UI --- src/components/pages/Roles/RoleTerm.tsx | 189 ++++++++++++++ .../pages/Roles/forms/RoleFormMember.tsx | 17 +- .../pages/Roles/forms/RoleFormTerms.tsx | 139 +++++++++++ .../Roles/forms/RoleTermEndDatePicker.tsx | 233 ++++++++++++++++++ src/components/pages/Roles/types.tsx | 2 +- 5 files changed, 573 insertions(+), 7 deletions(-) create mode 100644 src/components/pages/Roles/RoleTerm.tsx create mode 100644 src/components/pages/Roles/forms/RoleFormTerms.tsx create mode 100644 src/components/pages/Roles/forms/RoleTermEndDatePicker.tsx diff --git a/src/components/pages/Roles/RoleTerm.tsx b/src/components/pages/Roles/RoleTerm.tsx new file mode 100644 index 0000000000..e7e9f1dc4f --- /dev/null +++ b/src/components/pages/Roles/RoleTerm.tsx @@ -0,0 +1,189 @@ +import { Box, Flex, Icon, Text } from '@chakra-ui/react'; +import { Calendar, ClockCountdown } from '@phosphor-icons/react'; +import { format } from 'date-fns'; +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { zeroAddress } from 'viem'; +import { DETAILS_BOX_SHADOW } from '../../../constants/common'; +import { useGetDAOName } from '../../../hooks/DAO/useGetDAOName'; +import useAvatar from '../../../hooks/utils/useAvatar'; +import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; +import { DEFAULT_DATE_FORMAT } from '../../../utils'; +import { getChainIdFromPrefix } from '../../../utils/url'; +import Avatar from '../../ui/page/Header/Avatar'; + +function Container({ children, isTop = false }: { isTop?: boolean; children: React.ReactNode }) { + return ( + + {children} + + ); +} + +function RoleTermHeaderTitle() { + const { t } = useTranslation(['roles']); + const isCurrentTerm = true; + const termIndicatorText = + isCurrentTerm === undefined ? undefined : isCurrentTerm ? t('Current Term') : t('Next Term'); + return ( + + {t('Term 1')} + + {termIndicatorText} + + + ); +} + +function RoleTermHeaderStatus() { + const endDateTs = 0n; + const isCurrentTerm = false; + const isReadyToStart = false; + const isQueued = false; + + const statusText = useMemo(() => { + // is ready to start (show ready to start) + // is Queued (next term, show In Queue) + // is Active (show till end date) + // is Expired (show Expired) + if (isReadyToStart) { + return 'Ready to start'; + } + if (endDateTs < BigInt(Date.now())) { + return 'Expired'; + } + if (isQueued) { + // Next term + return 'In Queue'; + } + if (isCurrentTerm) { + // time left + return '30 d'; + } + + return; + }, [endDateTs, isCurrentTerm, isReadyToStart, isQueued]); + return ( + + + + {statusText} + + + ); +} + +function RoleTermHeader() { + return ( + + + + + + + ); +} + +function RoleTermMemberAddress() { + const memberAddress = zeroAddress; + const { t } = useTranslation(['roles']); + + const { addressPrefix } = useNetworkConfig(); + const { daoName: accountDisplayName } = useGetDAOName({ + address: memberAddress, + chainId: getChainIdFromPrefix(addressPrefix), + }); + const avatarURL = useAvatar(memberAddress); + return ( + + + {t('member')} + + + + + {accountDisplayName} + + + + ); +} + +function RoleTermEndDate() { + const endDateTs = Date.now() / 1000; + return ( + + + {'Ending'} + + + + + {format(new Date(endDateTs * 1000), DEFAULT_DATE_FORMAT)} + + + + ); +} + +export default function RoleTerm() { + return ( + + + + + + + + + + ); +} diff --git a/src/components/pages/Roles/forms/RoleFormMember.tsx b/src/components/pages/Roles/forms/RoleFormMember.tsx index 017babf6b1..42c2b5bc57 100644 --- a/src/components/pages/Roles/forms/RoleFormMember.tsx +++ b/src/components/pages/Roles/forms/RoleFormMember.tsx @@ -16,7 +16,7 @@ import { FileX, WarningDiamond, } from '@phosphor-icons/react'; -import { Field, FieldProps } from 'formik'; +import { Field, FieldProps, useFormikContext } from 'formik'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { DETAILS_BOX_SHADOW } from '../../../../constants/common'; @@ -25,6 +25,7 @@ import { AddressInput } from '../../../ui/forms/EthAddressInput'; import LabelWrapper from '../../../ui/forms/LabelWrapper'; import { ModalBase } from '../../../ui/modals/ModalBase'; import { RoleFormValues } from '../types'; +import RoleFormTerms from './RoleFormTerms'; function RoleMemberWearerInput() { const { t } = useTranslation('roles'); @@ -183,9 +184,9 @@ function RoleMemberConfirmationPortal({ {}} + onClose={onClose} isSearchInputModal={false} > (); + if (!!values.roleEditing?.isTermed) { + return ; + } return ( - <> + - + ); } diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx new file mode 100644 index 0000000000..557c4c40d8 --- /dev/null +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -0,0 +1,139 @@ +import { Box, Button, FormControl, Icon, Text } from '@chakra-ui/react'; +import { Plus } from '@phosphor-icons/react'; +import { Field, FieldProps, useFormikContext } from 'formik'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DETAILS_BOX_SHADOW } from '../../../../constants/common'; +import { AddressInput } from '../../../ui/forms/EthAddressInput'; +import LabelWrapper from '../../../ui/forms/LabelWrapper'; +import RoleTerm from '../RoleTerm'; +import { RoleFormValues } from '../types'; +import { RoleTermEndDatePicker } from './RoleTermEndDatePicker'; + +function RoleTermEndDateInput({ termIndex }: { termIndex: number }) { + const { t } = useTranslation('roles'); + return ( + + + {({ field, meta }: FieldProps) => ( + + + + )} + + + ); +} + +function RoleTermMemberInput({ termIndex }: { termIndex: number }) { + const { t } = useTranslation('roles'); + return ( + + + {({ + field, + form: { setFieldValue, setFieldTouched }, + meta, + }: FieldProps) => ( + + { + setFieldTouched(field.name, true); + }} + onChange={e => { + setFieldValue(field.name, e.target.value); + }} + /> + + )} + + + ); +} + +function RoleTermCreate({ termIndex }: { termIndex: number }) { + const { t } = useTranslation('roles'); + return ( + + + {t('Term 1')} + + + + + + + + ); +} + +export default function RoleFormTerms() { + const [showAddTerm, setShowAddTerm] = useState(false); + const { t } = useTranslation('roles'); + const { values } = useFormikContext(); + const roleTerms = values.roleEditing?.roleTerms || [{}]; + return ( + + + {/* @todo Hide when not creating terms */} + {(showAddTerm || !roleTerms.length) && } + {roleTerms.map((term, index) => ( + + ))} + + ); +} diff --git a/src/components/pages/Roles/forms/RoleTermEndDatePicker.tsx b/src/components/pages/Roles/forms/RoleTermEndDatePicker.tsx new file mode 100644 index 0000000000..bdbb81f993 --- /dev/null +++ b/src/components/pages/Roles/forms/RoleTermEndDatePicker.tsx @@ -0,0 +1,233 @@ +import { + Box, + Button, + Divider, + Flex, + Icon, + Menu, + MenuButton, + MenuList, + Show, + useBreakpointValue, +} from '@chakra-ui/react'; +import { ArrowRight, CalendarBlank, CaretLeft, CaretRight } from '@phosphor-icons/react'; +import { format } from 'date-fns'; +import { ReactNode, useState } from 'react'; +import { Calendar } from 'react-calendar'; +import { useTranslation } from 'react-i18next'; +import { SEXY_BOX_SHADOW_T_T } from '../../../../constants/common'; +import { DEFAULT_DATE_FORMAT } from '../../../../utils'; +import DraggableDrawer from '../../../ui/containers/DraggableDrawer'; +import { DatePickerTrigger } from '../DatePickerTrigger'; + +type DateOrNull = Date | null; +type OnDateChangeValue = DateOrNull | [DateOrNull, DateOrNull]; + +function DateDisplayBox({ date }: { date: Date | undefined }) { + const { t } = useTranslation('common'); + return ( + + + {(date && format(date, DEFAULT_DATE_FORMAT)) ?? t('select')} + + ); +} + +function SelectedDateDisplay({ + selectedDate, + selectedRange, + isRange, +}: { + selectedDate: Date | undefined; + selectedRange: [DateOrNull, DateOrNull]; + isRange?: boolean; +}) { + return !isRange ? ( + + {' '} + + ) : ( + + + + + + ); +} + +const isToday = (date: Date) => { + const today = new Date(); + return ( + date.getDate() === today.getDate() && + date.getMonth() === today.getMonth() && + date.getFullYear() === today.getFullYear() + ); +}; + +function RoleTermEndDatePickerContainer({ + children, + disabled, + selectedDate, +}: { + children: ReactNode[]; + disabled: boolean; + selectedDate: Date | undefined; +}) { + const [isDrawerOpen, setIsDrawerOpen] = useState(false); + const boxShadow = useBreakpointValue({ base: 'none', md: SEXY_BOX_SHADOW_T_T }); + const maxBoxW = useBreakpointValue({ base: '100%', md: '26.875rem' }); + return ( + <> + + + + {}} + onClose={() => setIsDrawerOpen(false)} + > + + {children} + + + + + + + + + + + {children} + + + + + + ); +} + +function TodayBox({ isTodaySelected }: { isTodaySelected: () => boolean }) { + // @dev @todo - This is a workaround to fix an issue with the dot not being centered on the current day. Gotta be a better way to fix this. + const todayDotLeftMargin = useBreakpointValue({ base: '4.5vw', md: '1.15rem' }); + return ( + + ); +} + +export function RoleTermEndDatePicker({ + selectedDate, + onChange, + minDate, + maxDate, + disabled, +}: { + onChange: (date: Date) => void; + selectedDate: Date | undefined; + minDate?: Date; + maxDate?: Date; + disabled: boolean; +}) { + const isTodaySelected = () => { + return !!selectedDate ? isToday(selectedDate) : false; + }; + + return ( + + + + {!disabled && ( + date.toString().slice(0, 2)} + prevLabel={} + nextLabel={} + next2Label={null} + prev2Label={null} + tileContent={({ date }) => + isToday(date) ? : null + } + onChange={(e: OnDateChangeValue) => { + if (e instanceof Date) { + onChange?.(e); + } + }} + /> + )} + + ); +} diff --git a/src/components/pages/Roles/types.tsx b/src/components/pages/Roles/types.tsx index eac5b579fb..446fed8b07 100644 --- a/src/components/pages/Roles/types.tsx +++ b/src/components/pages/Roles/types.tsx @@ -136,7 +136,7 @@ export interface RoleHatFormValue isTermed?: boolean; roleTerms?: { nominee?: string; - termEndDateTs?: number; + termEndDate?: Date; }[]; } From 1e414f2315e373c12fc88b64ce32d6aac3d5535c Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 17 Oct 2024 05:34:20 -0400 Subject: [PATCH 014/191] Refactor RoleTerm component and RoleFormTerms component - Refactor RoleTerm component to include a new prop `termStatus` to indicate the status of the term (current, queued, or expired). Update the component to display the term number and status accordingly. Also, import the `useDateTimeDisplay` helper function from the `dateTime` module. - Refactor RoleFormTerms component to sort the role terms based on the term end date. Add a new prop `termStatus` to the RoleTerm component to indicate the status of each term. Update the component to render the current term, next term, and expired terms based on their status. Also, update the translation strings in the `roles.json` file. --- src/components/pages/Roles/RoleTerm.tsx | 111 +++++++++++------ .../pages/Roles/forms/RoleFormTerms.tsx | 115 ++++++++++++++++-- src/i18n/locales/en/roles.json | 7 +- 3 files changed, 189 insertions(+), 44 deletions(-) diff --git a/src/components/pages/Roles/RoleTerm.tsx b/src/components/pages/Roles/RoleTerm.tsx index e7e9f1dc4f..8e635a0e86 100644 --- a/src/components/pages/Roles/RoleTerm.tsx +++ b/src/components/pages/Roles/RoleTerm.tsx @@ -3,8 +3,9 @@ import { Calendar, ClockCountdown } from '@phosphor-icons/react'; import { format } from 'date-fns'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { zeroAddress } from 'viem'; +import { Address } from 'viem'; import { DETAILS_BOX_SHADOW } from '../../../constants/common'; +import { useDateTimeDisplay } from '../../../helpers/dateTime'; import { useGetDAOName } from '../../../hooks/DAO/useGetDAOName'; import useAvatar from '../../../hooks/utils/useAvatar'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; @@ -12,6 +13,8 @@ import { DEFAULT_DATE_FORMAT } from '../../../utils'; import { getChainIdFromPrefix } from '../../../utils/url'; import Avatar from '../../ui/page/Header/Avatar'; +export type RoleTermStatus = 'current' | 'queued' | 'expired'; + function Container({ children, isTop = false }: { isTop?: boolean; children: React.ReactNode }) { return ( - {t('Term 1')} + {t('termNumber', { number: termNumber })} { - // is ready to start (show ready to start) - // is Queued (next term, show In Queue) - // is Active (show till end date) - // is Expired (show Expired) if (isReadyToStart) { - return 'Ready to start'; + return t('Ready to start'); } - if (endDateTs < BigInt(Date.now())) { - return 'Expired'; + if (termStatus === 'expired') { + return t('expired'); } - if (isQueued) { + if (termStatus === 'queued') { // Next term - return 'In Queue'; + return t('inQueue'); } - if (isCurrentTerm) { + if (termStatus === 'current') { // time left - return '30 d'; + return dateDisplay; } return; - }, [endDateTs, isCurrentTerm, isReadyToStart, isQueued]); + }, [isReadyToStart, dateDisplay, termStatus, t]); return ( - - + + ); } -function RoleTermMemberAddress() { - const memberAddress = zeroAddress; +function RoleTermMemberAddress({ memberAddress }: { memberAddress: Address }) { const { t } = useTranslation(['roles']); const { addressPrefix } = useNetworkConfig(); @@ -148,15 +175,15 @@ function RoleTermMemberAddress() { ); } -function RoleTermEndDate() { - const endDateTs = Date.now() / 1000; +function RoleTermEndDate({ termEndDate }: { termEndDate: Date }) { + const { t } = useTranslation(['roles']); return ( - {'Ending'} + {t('ending')} - {format(new Date(endDateTs * 1000), DEFAULT_DATE_FORMAT)} + {format(termEndDate, DEFAULT_DATE_FORMAT)} ); } -export default function RoleTerm() { +export default function RoleTerm({ + memberAddress, + termEndDate, + termStatus, + termNumber, +}: { + memberAddress: Address; + termEndDate: Date; + termNumber: number; + termStatus: RoleTermStatus; +}) { return ( - + - - + + diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 557c4c40d8..c7ffc9e4b0 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -1,12 +1,13 @@ -import { Box, Button, FormControl, Icon, Text } from '@chakra-ui/react'; +import { Box, Button, Flex, FormControl, Icon, Text } from '@chakra-ui/react'; import { Plus } from '@phosphor-icons/react'; import { Field, FieldProps, useFormikContext } from 'formik'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { getAddress, zeroAddress } from 'viem'; import { DETAILS_BOX_SHADOW } from '../../../../constants/common'; import { AddressInput } from '../../../ui/forms/EthAddressInput'; import LabelWrapper from '../../../ui/forms/LabelWrapper'; -import RoleTerm from '../RoleTerm'; +import RoleTerm, { RoleTermStatus } from '../RoleTerm'; import { RoleFormValues } from '../types'; import { RoleTermEndDatePicker } from './RoleTermEndDatePicker'; @@ -107,11 +108,99 @@ function RoleTermCreate({ termIndex }: { termIndex: number }) { ); } +function RoleTermRenderer({ + roleTerm, + termStatus, +}: { + roleTerm?: { + nominee?: string; + termEndDate?: Date; + termNumber: number; + }; + termStatus: RoleTermStatus; +}) { + if (!roleTerm?.nominee || !roleTerm?.termEndDate) { + return null; + } + return ( + + + + ); +} + +function RoleTermExpiredTerms({ + roleTerms, +}: { + roleTerms?: { + nominee?: string; + termEndDate?: Date; + termNumber: number; + }[]; +}) { + if (!roleTerms) { + return null; + } + return ( + + {roleTerms.map((term, index) => { + return ( + + ); + })} + + ); +} + export default function RoleFormTerms() { const [showAddTerm, setShowAddTerm] = useState(false); const { t } = useTranslation('roles'); const { values } = useFormikContext(); - const roleTerms = values.roleEditing?.roleTerms || [{}]; + const roleFormTerms = + values.roleEditing?.roleTerms + ?.sort( + (a, b) => (a.termEndDate ?? new Date()).getTime() - (b.termEndDate ?? new Date()).getTime(), + ) + .map((term, index) => ({ ...term, termNumber: index + 1 })) || + [ + { + nominee: zeroAddress, + termEndDate: new Date('2024-10-10'), + }, + { + nominee: zeroAddress, + termEndDate: new Date('2025-10-22'), + }, + { + nominee: zeroAddress, + termEndDate: new Date('2026-10-27'), + }, + { + nominee: zeroAddress, + termEndDate: new Date('2024-10-9'), + }, + ] + .sort( + (a, b) => (a.termEndDate ?? new Date()).getTime() - (b.termEndDate ?? new Date()).getTime(), + ) + .map((term, index) => ({ ...term, termNumber: index + 1 })); + + const expiredTerms = roleFormTerms.filter( + term => !!term.termEndDate && term.termEndDate < new Date(), + ); + // {assumption}: only 2 terms should be unexpired at a time + const terms = roleFormTerms.filter(term => !!term.termEndDate && term.termEndDate >= new Date()); + const currentTerm = terms[0]; + const nextTerm = terms[1]; return ( - {/* @todo Hide when not creating terms */} - {(showAddTerm || !roleTerms.length) && } - {roleTerms.map((term, index) => ( - - ))} + + {(showAddTerm || !roleFormTerms.length) && } + + + + ); } diff --git a/src/i18n/locales/en/roles.json b/src/i18n/locales/en/roles.json index be9cb7d4f9..1ccff6968b 100644 --- a/src/i18n/locales/en/roles.json +++ b/src/i18n/locales/en/roles.json @@ -97,5 +97,10 @@ "addTermLengthTitle": "Add a term length to this role?", "addTermConfirmationStatementDate": "Term role has a set expiration date.", "addTermConfirmationStatementPayment": "Current Payments tied to the role will be deleted.", - "addTermConfirmationStatementImmutable": "Once set, the role cannot be converted back to unlimited." + "addTermConfirmationStatementImmutable": "Once set, the role cannot be converted back to unlimited.", + "termNumber": "Term {{number}}", + "currentTerm": "Current Term", + "nextTerm": "Next Term", + "expired": "Expired", + "inQueue": "In Queue" } \ No newline at end of file From c60d62fa4e933a913b54416afd95a7ab8430fa26 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 17 Oct 2024 05:54:36 -0400 Subject: [PATCH 015/191] add accordian to hide expired roles --- .../pages/Roles/forms/RoleFormTerms.tsx | 81 ++++++++++++++++--- src/i18n/locales/en/roles.json | 3 +- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index c7ffc9e4b0..3db72156b2 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -1,5 +1,16 @@ -import { Box, Button, Flex, FormControl, Icon, Text } from '@chakra-ui/react'; -import { Plus } from '@phosphor-icons/react'; +import { + Accordion, + AccordionButton, + AccordionItem, + AccordionPanel, + Box, + Button, + Flex, + FormControl, + Icon, + Text, +} from '@chakra-ui/react'; +import { CaretDown, CaretRight, Plus } from '@phosphor-icons/react'; import { Field, FieldProps, useFormikContext } from 'formik'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -143,20 +154,68 @@ function RoleTermExpiredTerms({ termNumber: number; }[]; }) { + const { t } = useTranslation('roles'); if (!roleTerms) { return null; } return ( - {roleTerms.map((term, index) => { - return ( - - ); - })} + + + {({ isExpanded }) => ( + <> + + + + + {t('showExpiredTerms')} + + + + + {roleTerms.map((term, index) => { + return ( + + + + ); + })} + + + )} + + ); } diff --git a/src/i18n/locales/en/roles.json b/src/i18n/locales/en/roles.json index 1ccff6968b..6223b6966a 100644 --- a/src/i18n/locales/en/roles.json +++ b/src/i18n/locales/en/roles.json @@ -102,5 +102,6 @@ "currentTerm": "Current Term", "nextTerm": "Next Term", "expired": "Expired", - "inQueue": "In Queue" + "inQueue": "In Queue", + "showExpiredTerms": "Show expired Terms" } \ No newline at end of file From 2c923db916eec57259df34ee00f872d693b5c748 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:59:38 -0400 Subject: [PATCH 016/191] update confirmation model to match designs --- .../theme/custom/icons/DecentHourGlass.tsx | 58 ++++++++++++ .../pages/Roles/forms/RoleFormMember.tsx | 93 +++++++++++++------ src/i18n/locales/en/roles.json | 10 +- 3 files changed, 128 insertions(+), 33 deletions(-) create mode 100644 src/assets/theme/custom/icons/DecentHourGlass.tsx diff --git a/src/assets/theme/custom/icons/DecentHourGlass.tsx b/src/assets/theme/custom/icons/DecentHourGlass.tsx new file mode 100644 index 0000000000..29a90667ef --- /dev/null +++ b/src/assets/theme/custom/icons/DecentHourGlass.tsx @@ -0,0 +1,58 @@ +import { ComponentWithAs, createIcon, IconProps } from '@chakra-ui/react'; + +export const DecentHourGlass: ComponentWithAs<'svg', IconProps> = createIcon({ + displayName: 'DecentHourGlass', + viewBox: '0 0 46 68', + path: ( + + + + + + + + + + + + + ), +}); diff --git a/src/components/pages/Roles/forms/RoleFormMember.tsx b/src/components/pages/Roles/forms/RoleFormMember.tsx index 42c2b5bc57..02da5b2ed1 100644 --- a/src/components/pages/Roles/forms/RoleFormMember.tsx +++ b/src/components/pages/Roles/forms/RoleFormMember.tsx @@ -10,15 +10,17 @@ import { useDisclosure, } from '@chakra-ui/react'; import { - ArrowLineLeft, - CalendarX, ClockCountdown, - FileX, + HandCoins, + ListPlus, + ReceiptX, + Warning, WarningDiamond, } from '@phosphor-icons/react'; import { Field, FieldProps, useFormikContext } from 'formik'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { DecentHourGlass } from '../../../../assets/theme/custom/icons/DecentHourGlass'; import { DETAILS_BOX_SHADOW } from '../../../../constants/common'; import DraggableDrawer from '../../../ui/containers/DraggableDrawer'; import { AddressInput } from '../../../ui/forms/EthAddressInput'; @@ -74,13 +76,11 @@ function RoleMemberConfirmationScreen({ alignItems="center" gap={4} px={8} - maxW="24rem" + maxW="28 rem" > - - + - {t('addTermConfirmationStatementDate')} + + {t('termedRoleConfirmation-1')} + - + - {t('addTermConfirmationStatementPayment')} + + + {t('termedRoleConfirmation-2')} + - + + + {t('termedRoleConfirmation-3')} + + + + - {t('addTermConfirmationStatementImmutable')} + + {t('termedRoleConfirmation-4')} + + + {t('termedRoleConfirmation-warning')} + + @@ -140,7 +175,7 @@ function RoleMemberConfirmationScreen({ {t('confirm', { ns: 'common' })} - {showAddTerm && } + {showAddTerm && ( + + )} Date: Sat, 19 Oct 2024 18:20:09 -0400 Subject: [PATCH 024/191] update contract addresses --- src/assets/abi/DecentAutonomousAdminTempAbi.ts | 4 ++-- src/providers/NetworkConfig/networks/sepolia.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/abi/DecentAutonomousAdminTempAbi.ts b/src/assets/abi/DecentAutonomousAdminTempAbi.ts index 14cde76424..3aa4c238b6 100644 --- a/src/assets/abi/DecentAutonomousAdminTempAbi.ts +++ b/src/assets/abi/DecentAutonomousAdminTempAbi.ts @@ -51,8 +51,8 @@ export default [ type: 'uint256', }, { - internalType: 'contract ISablierV2LockupLinear', - name: 'sablierV2LockupLinear', + internalType: 'contract ISablierV2Lockup', + name: 'sablierV2Lockup', type: 'address', }, ], diff --git a/src/providers/NetworkConfig/networks/sepolia.ts b/src/providers/NetworkConfig/networks/sepolia.ts index 992238624e..8cedb11bb2 100644 --- a/src/providers/NetworkConfig/networks/sepolia.ts +++ b/src/providers/NetworkConfig/networks/sepolia.ts @@ -80,8 +80,8 @@ export const sepoliaConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), - decentHatsMasterCopy: getAddress('0xaFdD339cE4Ed6638a5fba3147a2F0e4EF6d5f67a'), - decentAutonomousAdminMasterCopy: getAddress('0xd8784CEeC9cbA6c7eF31849Dd2c708c2AFc37b36'), + decentHatsMasterCopy: getAddress('0xb588Af5A2C5725caee72Be9DC6C776c8b5527915'), + decentAutonomousAdminMasterCopy: getAddress('0xCF9F5A1AD7dFFEE35a23d48848CD1Bc0Ccb6F74a'), decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', From d4abbc729ed09e4e2b228770617ddaeefc5f9d56 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 19 Oct 2024 18:20:34 -0400 Subject: [PATCH 025/191] updates to topHat creation workflow --- src/hooks/utils/useCreateRoles.ts | 55 +++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/hooks/utils/useCreateRoles.ts b/src/hooks/utils/useCreateRoles.ts index 88795f7582..bd2c39fb3c 100644 --- a/src/hooks/utils/useCreateRoles.ts +++ b/src/hooks/utils/useCreateRoles.ts @@ -58,6 +58,7 @@ export default function useCreateRoles() { keyValuePairs, sablierV2LockupLinear, decentHatsMasterCopy, + decentAutonomousAdminMasterCopy, zodiacModuleProxyFactory, }, } = useNetworkConfig(); @@ -115,7 +116,7 @@ export default function useCreateRoles() { maxSupply: 1, details, imageURI: '', - isMutable: true, + isMutable: !isTermed, wearer: wearer, isTermed, termedParams, @@ -193,6 +194,23 @@ export default function useCreateRoles() { }, [], ); + const parseRoleTermsFromFormRoleTerms = useCallback( + (formRoleTerms: { termEndDate?: Date; nominee?: string }[]) => { + return formRoleTerms.map(term => { + if (term.termEndDate === undefined) { + throw new Error('Term end date of added Role is undefined.'); + } + if (term.nominee === undefined) { + throw new Error('Nominee of added Role is undefined.'); + } + return { + termEndDateTs: BigInt(term.termEndDate.getTime() / 1000), + nominatedWearers: [getAddress(term.nominee)], + }; + }); + }, + [], + ); const createHatStructsForNewTreeFromRolesFormValues = useCallback( async (modifiedRoles: RoleHatFormValueEdited[]) => { @@ -207,22 +225,29 @@ export default function useCreateRoles() { } const sablierPayments = parseSablierPaymentsFromFormRolePayments(role.payments ?? []); + const roleTerms = parseRoleTermsFromFormRoleTerms(role.roleTerms ?? []); + + // @note for new termed roles, we set the first wearer to the first nominee + const wearer = role.isTermed + ? getAddress(roleTerms[0].nominatedWearers[0]) + : getAddress(role.wearer); + return createHatStructWithPayments( role.name, role.description, - getAddress(role.wearer), + wearer, sablierPayments, role.isTermed ?? false, - // @todo fix this - role.roleTerms?.map(term => ({ - termEndDateTs: 0n, - nominatedWearers: [zeroAddress], - })) ?? [], + roleTerms, ); }), ); }, - [createHatStructWithPayments, parseSablierPaymentsFromFormRolePayments], + [ + createHatStructWithPayments, + parseSablierPaymentsFromFormRolePayments, + parseRoleTermsFromFormRoleTerms, + ], ); const predictSmartAccount = useCallback( @@ -248,10 +273,7 @@ export default function useCreateRoles() { if (!daoAddress) { throw new Error('Can not create top hat without DAO Address'); } - // @todo remove when published to all networks - if (!decentHatsMasterCopy) { - throw new Error('Can not create top hat without DecentHatsV2MasterCopy'); - } + const enableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'enableModule', @@ -298,8 +320,8 @@ export default function useCreateRoles() { throw new Error('Could not find module'); } const addedHats = await createHatStructsForNewTreeFromRolesFormValues(modifiedHats); + console.log('🚀 ~ addedHats:', addedHats); const createAndDeclareTreeData = encodeFunctionData({ - // @note this should be lastest version of DecentHats // @todo replace with published abi from package abi: DecentHatsTempAbi, functionName: 'createAndDeclareTree', @@ -316,8 +338,7 @@ export default function useCreateRoles() { hatsModuleFactory: HATS_MODULES_FACTORY_ADDRESS, hatsElectionEligibilityImplementation: getAddress(module.implementationAddress), moduleProxyFactory: zodiacModuleProxyFactory, - // @note this should be lastest version of DecentHats - decentAutonomousAdminMasterCopy: decentHatsMasterCopy, + decentAutonomousAdminMasterCopy: decentAutonomousAdminMasterCopy, }, ], }); @@ -333,6 +354,7 @@ export default function useCreateRoles() { daoAddress, daoName, decentHatsMasterCopy, + decentAutonomousAdminMasterCopy, erc6551Registry, hatsAccount1ofNMasterCopy, hatsDetailsBuilder, @@ -364,7 +386,6 @@ export default function useCreateRoles() { mutableArgs: [firstTermEnd], }); - // @todo should this salt generation be the same as in DecentHats Contract? const salt = BigInt(generateSalt(encodedMutableArgs, getRandomBytes())); const createElectionEligibilityInstanceTx = { calldata: encodeFunctionData({ @@ -1114,7 +1135,7 @@ export default function useCreateRoles() { let proposalData: ProposalExecuteData; try { - if (!hatsTreeId) { + if (!!hatsTreeId) { // This safe has no top hat, so we prepare a proposal to create one. This will also create an admin hat, // along with any other hats that are added. From 13e4e15f6b4875ecd57aa64de980303d3988cb97 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sun, 20 Oct 2024 03:57:59 -0400 Subject: [PATCH 026/191] clean up 'new' term workflow --- src/hooks/utils/useCreateRoles.ts | 69 +++++++++++-------------------- 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/src/hooks/utils/useCreateRoles.ts b/src/hooks/utils/useCreateRoles.ts index bd2c39fb3c..f394628185 100644 --- a/src/hooks/utils/useCreateRoles.ts +++ b/src/hooks/utils/useCreateRoles.ts @@ -20,7 +20,6 @@ import { HatsElectionsEligibilityAbi } from '../../assets/abi/HatsElectionsEligi import { EditBadgeStatus, - HATS_ADDRESS, HatStruct, HatStructWithPayments, RoleFormValues, @@ -320,7 +319,6 @@ export default function useCreateRoles() { throw new Error('Could not find module'); } const addedHats = await createHatStructsForNewTreeFromRolesFormValues(modifiedHats); - console.log('🚀 ~ addedHats:', addedHats); const createAndDeclareTreeData = encodeFunctionData({ // @todo replace with published abi from package abi: DecentHatsTempAbi, @@ -459,7 +457,7 @@ export default function useCreateRoles() { [createHatStruct, hatsProtocol], ); const createNewTermedHatTxs = useCallback( - async (formRole: RoleHatFormValueEdited, adminHatId: bigint) => { + async (formRole: RoleHatFormValueEdited, adminHatId: bigint, topHatAccount: Address) => { if (formRole.name === undefined || formRole.description === undefined) { throw new Error('Name or description of added Role is undefined.'); } @@ -467,40 +465,31 @@ export default function useCreateRoles() { if (formRole.wearer === undefined) { throw new Error('Member of added Role is undefined.'); } - if (formRole.roleTerms?.[0].termEndDate === undefined) { - throw new Error('Term end date of added Role is undefined.'); - } - if (formRole.roleTerms?.[0].nominee === undefined) { - throw new Error('Nominee of added Role is undefined.'); + if (formRole.roleTerms === undefined || formRole.roleTerms.length === 0) { + throw new Error('Role terms of added Role is undefined.'); } + const roleTerms = parseRoleTermsFromFormRoleTerms(formRole.roleTerms); let firstWearer = getAddress(formRole.wearer); let txData: { calldata: Hex; targetAddress: Address }[] = []; - let eligibilityModule = HATS_ADDRESS; const { electionDeployModuleTx, predictedElectionEligibilityInstance } = await createEligibilityModuleTx( BigInt(formRole.id), // @todo fix this to be the correct term end date - BigInt(Date.now()), + roleTerms[0].termEndDateTs, adminHatId, ); txData.push(electionDeployModuleTx); - eligibilityModule = predictedElectionEligibilityInstance; - firstWearer = getAddress(formRole.roleTerms[0].nominee); + const eligibilityModule = predictedElectionEligibilityInstance; + firstWearer = getAddress(roleTerms[0].nominatedWearers[0]); const hatStruct = await createHatStruct( formRole.name, formRole.description, getAddress(firstWearer), true, - [ - { - // @todo fix this to be the correct term end date - termEndDateTs: BigInt(Date.now()), - nominatedWearers: [getAddress(formRole.roleTerms[0].nominee)], - }, - ], + roleTerms, ); txData.push({ @@ -511,41 +500,29 @@ export default function useCreateRoles() { adminHatId, // adminHatId hatStruct.details, // details hatStruct.maxSupply, // maxSupply - HATS_ADDRESS, // toggleModule eligibilityModule, // eligibilityModule + topHatAccount, // toggleModule !formRole.isTermed ? hatStruct.isMutable : false, // isMutable hatStruct.wearer, // wearer ], }), targetAddress: hatsProtocol, }); - if (eligibilityModule !== HATS_ADDRESS) { - if (formRole.roleTerms?.[0].termEndDate === undefined) { - throw new Error('Term end date of added Role is undefined.'); - } - // create transactions to start first term right away - txData.push({ - calldata: encodeFunctionData({ - abi: HatsElectionsEligibilityAbi, - functionName: 'elect', - // @todo fix this to be the correct term end date - args: [BigInt(Date.now()), [hatStruct.wearer]], - }), - targetAddress: eligibilityModule, - }); - txData.push({ - calldata: encodeFunctionData({ - abi: HatsElectionsEligibilityAbi, - functionName: 'startNextTerm', - args: [], - }), - targetAddress: eligibilityModule, - }); - } + + // create transactions to start first term right away + txData.push({ + calldata: encodeFunctionData({ + abi: HatsElectionsEligibilityAbi, + functionName: 'elect', + // @todo fix this to be the correct term end date + args: [roleTerms[0].termEndDateTs, [hatStruct.wearer]], + }), + targetAddress: eligibilityModule, + }); return txData; }, - [createHatStruct, hatsProtocol, createEligibilityModuleTx], + [createHatStruct, hatsProtocol, createEligibilityModuleTx, parseRoleTermsFromFormRoleTerms], ); const mintHatTx = useCallback( @@ -707,7 +684,7 @@ export default function useCreateRoles() { }); newHatCount++; if (formHat.isTermed) { - allTxs.push(...(await createNewTermedHatTxs(formHat, adminHatId))); + allTxs.push(...(await createNewTermedHatTxs(formHat, adminHatId, topHatAccount))); } else { allTxs.push(await createNewHatTx(formHat, adminHatId, topHatAccount)); } @@ -1135,7 +1112,7 @@ export default function useCreateRoles() { let proposalData: ProposalExecuteData; try { - if (!!hatsTreeId) { + if (!hatsTreeId) { // This safe has no top hat, so we prepare a proposal to create one. This will also create an admin hat, // along with any other hats that are added. From 6351d094eda793a34dad7b9dfbc5b55b3266352d Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sun, 20 Oct 2024 15:55:20 -0400 Subject: [PATCH 027/191] 'get' role terms --- .../Roles/forms/RoleFormCreateProposal.tsx | 15 +++++++ .../pages/Roles/forms/RoleFormTerms.tsx | 4 +- src/components/pages/Roles/types.tsx | 2 +- src/store/roles/rolesStoreUtils.ts | 43 ++++++++++++++++++- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx b/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx index 1c12019a50..d5ab3121c4 100644 --- a/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx +++ b/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx @@ -91,6 +91,19 @@ export default function RoleFormCreateProposal({ close }: { close: () => void }) cause: roleHat, }); } + const roleTerms = + roleHat.roleTerms?.map(term => { + if (!term.termEndDate || term.nominee === undefined || term.newStatus === undefined) { + throw new Error('Role term missing data', { + cause: term, + }); + } + return { + termEndDate: term.termEndDate, + nominee: getAddress(term.nominee), + newStatus: term.newStatus, + }; + }) || []; return { ...roleHat, editedRole: roleHat.editedRole, @@ -98,6 +111,8 @@ export default function RoleFormCreateProposal({ close }: { close: () => void }) name: roleHat.name, description: roleHat.description, wearer: getAddress(roleHat.wearer), + roleTerms, + isTermed: roleHat.isTermed ?? false, payments: roleHat.payments ? roleHat.payments.map(payment => { if (!payment.startDate || !payment.endDate || !payment.amount || !payment.asset) { diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 840f7ecb12..9f80d400a6 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -95,7 +95,7 @@ function RoleTermCreate({ isNextTerm, termIndex }: { termIndex: number; isNextTe flexDirection="column" gap="1rem" > - {t('Term 1')} + {t('termNumber', { number: termIndex })} {showAddTerm && ( )} diff --git a/src/components/pages/Roles/types.tsx b/src/components/pages/Roles/types.tsx index cec16b8e85..e2fde6fec9 100644 --- a/src/components/pages/Roles/types.tsx +++ b/src/components/pages/Roles/types.tsx @@ -126,7 +126,7 @@ export interface DurationBreakdown { } export interface RoleHatFormValue - extends Partial> { + extends Partial> { id: Hex; wearer?: string; payments?: SablierPaymentFormValues[]; diff --git a/src/store/roles/rolesStoreUtils.ts b/src/store/roles/rolesStoreUtils.ts index b272e17b29..ee168c4d15 100644 --- a/src/store/roles/rolesStoreUtils.ts +++ b/src/store/roles/rolesStoreUtils.ts @@ -1,6 +1,7 @@ import { Tree, Hat } from '@hatsprotocol/sdk-v1-subgraph'; -import { Address, Hex, PublicClient, getContract } from 'viem'; +import { Address, Hex, PublicClient, getAddress, getContract } from 'viem'; import ERC6551RegistryAbi from '../../assets/abi/ERC6551RegistryAbi'; +import { HatsElectionsEligibilityAbi } from '../../assets/abi/HatsElectionsEligibilityAbi'; import { SablierPayment } from '../../components/pages/Roles/types'; import { ERC6551_REGISTRY_SALT } from '../../constants/common'; @@ -51,6 +52,8 @@ interface RolesStoreData { export interface DecentRoleHat extends DecentHat { wearer: Address; eligibility?: `0x${string}`; + roleTerms: { nominee: Address; termEndDate: Date }[]; + isTermed: boolean; } export interface DecentTree { @@ -243,7 +246,41 @@ export const sanitize = async ( tokenId: BigInt(rawHat.id), publicClient, }); - + let roleTerms: { + nominee: Address; + termEndDate: Date; + }[] = []; + let isTermed: boolean = false; + if (rawHat.eligibility) { + // @dev check if the eligibility is an election contract + try { + const electionContract = getContract({ + abi: HatsElectionsEligibilityAbi, + address: rawHat.eligibility, + client: publicClient, + }); + const rawTerms = await electionContract.getEvents.ElectionCompleted({ + fromBlock: 0n, + }); + roleTerms = rawTerms.map(term => { + const nominee = term.args.winners?.[0]; + const termEnd = term.args.termEnd; + if (!nominee) { + throw new Error('No nominee in the election'); + } + if (!termEnd) { + throw new Error('No term end in the election'); + } + return { + nominee: getAddress(nominee), + termEndDate: new Date(Number(termEnd.toString()) * 1000), + }; + }); + isTermed = true; + } catch { + console.error('Failed to get election terms or not a valid election contract'); + } + } roleHats.push({ id: rawHat.id, prettyId: rawHat.prettyId ?? '', @@ -252,6 +289,8 @@ export const sanitize = async ( wearer: rawHat.wearers![0].id, smartAddress: roleHatSmartAddress, eligibility: rawHat.eligibility, + roleTerms, + isTermed, }); } From bd3afe3667e37842266632963f5835426f943432 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sun, 20 Oct 2024 16:32:49 -0400 Subject: [PATCH 028/191] remove test button --- .../pages/Roles/forms/RoleFormTabs.tsx | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormTabs.tsx b/src/components/pages/Roles/forms/RoleFormTabs.tsx index d93cde363f..c1d06f62c5 100644 --- a/src/components/pages/Roles/forms/RoleFormTabs.tsx +++ b/src/components/pages/Roles/forms/RoleFormTabs.tsx @@ -64,35 +64,6 @@ export default function RoleFormTabs({ return ( <> - {/* */} {t('roleInfo')} From 4618bc6ab311fd2fa6578fef1f2ef50681df9f4c Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sun, 20 Oct 2024 16:41:20 -0400 Subject: [PATCH 029/191] bugfix: term changing when input changes --- src/components/pages/Roles/forms/RoleFormTerms.tsx | 12 ++++++------ src/hooks/schemas/roles/useRolesSchema.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 9f80d400a6..b57a80c034 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -225,7 +225,7 @@ function RoleTermExpiredTerms({ } export default function RoleFormTerms() { - const [showAddTerm, setShowAddTerm] = useState(false); + const [newTermIndex, setNewTermIndex] = useState(); const { t } = useTranslation('roles'); const { values } = useFormikContext(); @@ -243,7 +243,7 @@ export default function RoleFormTerms() { // @dev shows the term form when there are no terms useEffect(() => { if (!roleFormTerms.length) { - setShowAddTerm(true); + setNewTermIndex(0); } }, [roleFormTerms]); @@ -261,9 +261,9 @@ export default function RoleFormTerms() { variant="secondary" size="sm" mb={4} - isDisabled={showAddTerm || terms.length > 2 || !roleFormTerms.length} + isDisabled={!!newTermIndex || terms.length > 2 || !roleFormTerms.length} onClick={() => { - setShowAddTerm(true); + setNewTermIndex(roleFormTerms.length + 1); }} > - {showAddTerm && ( + {newTermIndex && ( )} diff --git a/src/hooks/schemas/roles/useRolesSchema.ts b/src/hooks/schemas/roles/useRolesSchema.ts index 88b28ed335..6feb80edd4 100644 --- a/src/hooks/schemas/roles/useRolesSchema.ts +++ b/src/hooks/schemas/roles/useRolesSchema.ts @@ -136,9 +136,9 @@ export const useRolesSchema = () => { message: t('roleInfoErrorTermEndDateInvalid'), test: (termEndDate, cxt) => { if (!termEndDate || !cxt.from) return true; - const [, { value: terms }] = cxt.from; + const [, { value: role }] = cxt.from; // remove the last element from terms and create a new array with the rest of the elements - const previousTerms = terms.slice(0, -1); + const previousTerms = role.roleTerms.slice(0, -1); if ( previousTerms.every( (term: { termEndDate: Date }) => From 0a9b1bcfcef7b7cb0aadadae2d6353a4f535f7e8 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:25:47 -0400 Subject: [PATCH 030/191] move sort and term number add to top level --- .../Roles/forms/RoleFormCreateProposal.tsx | 8 +++- .../pages/Roles/forms/RoleFormTerms.tsx | 8 +--- src/components/pages/Roles/types.tsx | 1 + src/store/roles/rolesStoreUtils.ts | 37 +++++++++++-------- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx b/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx index d5ab3121c4..63479ce454 100644 --- a/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx +++ b/src/components/pages/Roles/forms/RoleFormCreateProposal.tsx @@ -93,7 +93,12 @@ export default function RoleFormCreateProposal({ close }: { close: () => void }) } const roleTerms = roleHat.roleTerms?.map(term => { - if (!term.termEndDate || term.nominee === undefined || term.newStatus === undefined) { + if ( + !term.termEndDate || + term.nominee === undefined || + term.newStatus === undefined || + term.termNumber === undefined + ) { throw new Error('Role term missing data', { cause: term, }); @@ -101,6 +106,7 @@ export default function RoleFormCreateProposal({ close }: { close: () => void }) return { termEndDate: term.termEndDate, nominee: getAddress(term.nominee), + termNumber: term.termNumber, newStatus: term.newStatus, }; }) || []; diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index b57a80c034..30e8f8a64a 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -230,13 +230,7 @@ export default function RoleFormTerms() { const { values } = useFormikContext(); const roleFormTerms = useMemo( - () => - values.roleEditing?.roleTerms - ?.sort( - (a, b) => - (a.termEndDate ?? new Date()).getTime() - (b.termEndDate ?? new Date()).getTime(), - ) - .map((term, index) => ({ ...term, termNumber: index + 1 })) || [], + () => values.roleEditing?.roleTerms || [], [values.roleEditing?.roleTerms], ); diff --git a/src/components/pages/Roles/types.tsx b/src/components/pages/Roles/types.tsx index e2fde6fec9..cc296c49ce 100644 --- a/src/components/pages/Roles/types.tsx +++ b/src/components/pages/Roles/types.tsx @@ -138,6 +138,7 @@ export interface RoleHatFormValue newStatus?: 'current' | 'next'; nominee?: string; termEndDate?: Date; + termNumber: number; }[]; } diff --git a/src/store/roles/rolesStoreUtils.ts b/src/store/roles/rolesStoreUtils.ts index ee168c4d15..9fb5188463 100644 --- a/src/store/roles/rolesStoreUtils.ts +++ b/src/store/roles/rolesStoreUtils.ts @@ -52,7 +52,7 @@ interface RolesStoreData { export interface DecentRoleHat extends DecentHat { wearer: Address; eligibility?: `0x${string}`; - roleTerms: { nominee: Address; termEndDate: Date }[]; + roleTerms: { nominee: Address; termEndDate: Date; termNumber: number }[]; isTermed: boolean; } @@ -249,6 +249,7 @@ export const sanitize = async ( let roleTerms: { nominee: Address; termEndDate: Date; + termNumber: number; }[] = []; let isTermed: boolean = false; if (rawHat.eligibility) { @@ -262,20 +263,26 @@ export const sanitize = async ( const rawTerms = await electionContract.getEvents.ElectionCompleted({ fromBlock: 0n, }); - roleTerms = rawTerms.map(term => { - const nominee = term.args.winners?.[0]; - const termEnd = term.args.termEnd; - if (!nominee) { - throw new Error('No nominee in the election'); - } - if (!termEnd) { - throw new Error('No term end in the election'); - } - return { - nominee: getAddress(nominee), - termEndDate: new Date(Number(termEnd.toString()) * 1000), - }; - }); + roleTerms = rawTerms + .map(term => { + const nominee = term.args.winners?.[0]; + const termEnd = term.args.termEnd; + if (!nominee) { + throw new Error('No nominee in the election'); + } + if (!termEnd) { + throw new Error('No term end in the election'); + } + return { + nominee: getAddress(nominee), + termEndDate: new Date(Number(termEnd.toString()) * 1000), + }; + }) + .sort( + (a, b) => + (a.termEndDate ?? new Date()).getTime() - (b.termEndDate ?? new Date()).getTime(), + ) + .map((term, index) => ({ ...term, termNumber: index + 1 })); isTermed = true; } catch { console.error('Failed to get election terms or not a valid election contract'); From 5fb5de803cb947b78015fa7cc8e81cf3008cc4bb Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sun, 20 Oct 2024 21:37:33 -0400 Subject: [PATCH 031/191] add close button to add term form --- .../pages/Roles/forms/RoleFormTerms.tsx | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 30e8f8a64a..3dac8c878e 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -8,9 +8,10 @@ import { Flex, FormControl, Icon, + IconButton, Text, } from '@chakra-ui/react'; -import { CaretDown, CaretRight, Plus } from '@phosphor-icons/react'; +import { CaretDown, CaretRight, Plus, X } from '@phosphor-icons/react'; import { Field, FieldProps, useFormikContext } from 'formik'; import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -81,22 +82,44 @@ function RoleTermMemberInput({ termIndex }: { termIndex: number }) { ); } -function RoleTermCreate({ isNextTerm, termIndex }: { termIndex: number; isNextTerm: boolean }) { +function RoleTermCreate({ + onClose, + isNextTerm, + termIndex, +}: { + termIndex: number; + isNextTerm: boolean; + onClose: () => void; +}) { const { t } = useTranslation('roles'); - const { setFieldValue } = useFormikContext(); + const { values, setFieldValue } = useFormikContext(); return ( - {t('termNumber', { number: termIndex })} - + { + // remove term from the form + setFieldValue( + 'roleEditing.roleTerms', + values?.roleEditing?.roleTerms?.filter((_, index) => index !== termIndex), + ); + onClose(); + }} + /> + setNewTermIndex(undefined)} /> )} Date: Sun, 20 Oct 2024 23:16:26 -0400 Subject: [PATCH 032/191] add copy address to term member --- src/components/pages/Roles/RoleTerm.tsx | 26 +++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/components/pages/Roles/RoleTerm.tsx b/src/components/pages/Roles/RoleTerm.tsx index 8e635a0e86..2134e1f9da 100644 --- a/src/components/pages/Roles/RoleTerm.tsx +++ b/src/components/pages/Roles/RoleTerm.tsx @@ -1,5 +1,5 @@ import { Box, Flex, Icon, Text } from '@chakra-ui/react'; -import { Calendar, ClockCountdown } from '@phosphor-icons/react'; +import { Calendar, ClockCountdown, Copy } from '@phosphor-icons/react'; import { format } from 'date-fns'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -8,6 +8,7 @@ import { DETAILS_BOX_SHADOW } from '../../../constants/common'; import { useDateTimeDisplay } from '../../../helpers/dateTime'; import { useGetDAOName } from '../../../hooks/DAO/useGetDAOName'; import useAvatar from '../../../hooks/utils/useAvatar'; +import { useCopyText } from '../../../hooks/utils/useCopyText'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { DEFAULT_DATE_FORMAT } from '../../../utils'; import { getChainIdFromPrefix } from '../../../utils/url'; @@ -147,6 +148,7 @@ function RoleTermMemberAddress({ memberAddress }: { memberAddress: Address }) { chainId: getChainIdFromPrefix(addressPrefix), }); const avatarURL = useAvatar(memberAddress); + const copyToClipboard = useCopyText(); return ( - copyToClipboard(memberAddress)} > - {accountDisplayName} - + + {accountDisplayName} + + + ); From 3ac056634d3f4bada7704188fb5d0c3895e36d4c Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:05:27 -0400 Subject: [PATCH 033/191] add status colors --- src/components/pages/Roles/RoleTerm.tsx | 49 +++++++++++++++++++++---- src/i18n/locales/en/roles.json | 4 +- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/components/pages/Roles/RoleTerm.tsx b/src/components/pages/Roles/RoleTerm.tsx index 2134e1f9da..254b7637f7 100644 --- a/src/components/pages/Roles/RoleTerm.tsx +++ b/src/components/pages/Roles/RoleTerm.tsx @@ -71,27 +71,60 @@ function RoleTermHeaderStatus({ termEndDate: Date; termStatus: RoleTermStatus; }) { + // @todo implement isReadyToStart const isReadyToStart = false; const { t } = useTranslation(['roles']); const dateDisplay = useDateTimeDisplay(termEndDate); const statusText = useMemo(() => { + const statusTextData = { + ended: { + text: t('ended'), + textColor: 'neutral-6', + iconColor: 'neutral-6', + }, + inQueue: { + text: t('inQueue'), + textColor: 'neutral-7', + iconColor: 'lilac-0', + }, + readyToStart: { + text: t('readyToStart'), + textColor: 'neutral-7', + iconColor: 'lilac-0', + }, + active: { + text: dateDisplay, + textColor: 'neutral-7', + iconColor: 'lilac-0', + }, + // @todo implement revoked tx + revoked: { + text: t('revoked'), + textColor: 'red-1', + iconColor: 'red-1', + }, + }; if (isReadyToStart) { - return t('Ready to start'); + return statusTextData.readyToStart; } if (termStatus === 'expired') { - return t('expired'); + return statusTextData.ended; } if (termStatus === 'queued') { // Next term - return t('inQueue'); + return statusTextData.inQueue; } if (termStatus === 'current') { // time left - return dateDisplay; + return statusTextData.active; } - return; + return { + text: undefined, + textColor: undefined, + iconColor: undefined, + }; }, [isReadyToStart, dateDisplay, termStatus, t]); return ( - {statusText} + {statusText.text} ); diff --git a/src/i18n/locales/en/roles.json b/src/i18n/locales/en/roles.json index 5bef4e4c8e..4cec43d2c9 100644 --- a/src/i18n/locales/en/roles.json +++ b/src/i18n/locales/en/roles.json @@ -98,8 +98,10 @@ "termNumber": "Term {{number}}", "currentTerm": "Current Term", "nextTerm": "Next Term", - "expired": "Expired", + "ended": "Ended", "inQueue": "In Queue", + "revoked": "Revoked", + "readyToStart": "Ready to Start", "showExpiredTerms": "Show expired Terms", "termedRoleConfirmation-1": "Define the length of time a member can hold this role.", "termedRoleConfirmation-2": "Queue up the next term at any time during the current term.", From cf08c9b5e4a6419413ead97b7f4e7c1d7087a6b3 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:39:00 -0400 Subject: [PATCH 034/191] pass correct index --- src/components/pages/Roles/forms/RoleFormTerms.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 3dac8c878e..60272b5d20 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -104,7 +104,7 @@ function RoleTermCreate({ justifyContent="space-between" w="full" > - {t('termNumber', { number: termIndex })} + {t('termNumber', { number: termIndex + 1 })} 2 || !roleFormTerms.length} onClick={() => { - setNewTermIndex(roleFormTerms.length + 1); + setNewTermIndex(roleFormTerms.length); }} > Date: Mon, 21 Oct 2024 01:58:29 -0400 Subject: [PATCH 035/191] fix expired ordering --- src/components/pages/Roles/forms/RoleFormTerms.tsx | 11 ++++++++--- src/store/roles/rolesStoreUtils.ts | 5 +---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 60272b5d20..6c3a722514 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -264,9 +264,14 @@ export default function RoleFormTerms() { } }, [roleFormTerms]); - const expiredTerms = roleFormTerms.filter( - term => !!term.termEndDate && term.termEndDate < new Date(), - ); + const expiredTerms = roleFormTerms + .filter(term => !!term.termEndDate && term.termEndDate < new Date()) + .sort((a, b) => { + if (!a.termEndDate || !b.termEndDate) { + return 0; + } + return b.termEndDate.getTime() - a.termEndDate.getTime(); + }); // {assumption}: only 2 terms should be unexpired at a time const terms = roleFormTerms.filter(term => !!term.termEndDate && term.termEndDate >= new Date()); diff --git a/src/store/roles/rolesStoreUtils.ts b/src/store/roles/rolesStoreUtils.ts index 9fb5188463..f4a67fc3d9 100644 --- a/src/store/roles/rolesStoreUtils.ts +++ b/src/store/roles/rolesStoreUtils.ts @@ -278,10 +278,7 @@ export const sanitize = async ( termEndDate: new Date(Number(termEnd.toString()) * 1000), }; }) - .sort( - (a, b) => - (a.termEndDate ?? new Date()).getTime() - (b.termEndDate ?? new Date()).getTime(), - ) + .sort((a, b) => a.termEndDate.getTime() - b.termEndDate.getTime()) .map((term, index) => ({ ...term, termNumber: index + 1 })); isTermed = true; } catch { From 8fda6a573f65eb3c8cc4127a4bf763cb6683b052 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:38:29 -0400 Subject: [PATCH 036/191] remove unused variant --- .../theme/components/button/button.variants.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/assets/theme/components/button/button.variants.ts b/src/assets/theme/components/button/button.variants.ts index 95c04a7255..6be8be51d3 100644 --- a/src/assets/theme/components/button/button.variants.ts +++ b/src/assets/theme/components/button/button.variants.ts @@ -45,20 +45,6 @@ const secondary = defineStyle({ }, }); -const secondaryRed = defineStyle({ - border: '1px solid', - borderColor: 'red-1', - color: 'red-1', - _hover: { - borderColor: 'red-0', - color: 'red-0', - }, - _active: { - borderColor: 'red-0', - color: 'red-0', - }, -}); - const tertiaryDisabled = { color: 'neutral-5', }; @@ -110,7 +96,6 @@ const stepper = defineStyle({ const buttonVariants = { primary, secondary, - secondaryRed, tertiary, stepper, }; From 37d2f18d995fe34807f80145bee035cc6aa5f9a8 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:03:26 -0400 Subject: [PATCH 037/191] fix conditional --- src/components/pages/Roles/forms/RoleFormTerms.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 6c3a722514..0a6fe28d2a 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -298,7 +298,7 @@ export default function RoleFormTerms() { flexDir="column" gap={4} > - {newTermIndex && ( + {newTermIndex !== undefined && ( Date: Mon, 21 Oct 2024 11:50:59 -0400 Subject: [PATCH 038/191] update typing --- src/store/roles/rolesStoreUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/roles/rolesStoreUtils.ts b/src/store/roles/rolesStoreUtils.ts index f4a67fc3d9..222a446a78 100644 --- a/src/store/roles/rolesStoreUtils.ts +++ b/src/store/roles/rolesStoreUtils.ts @@ -31,7 +31,7 @@ interface DecentHat { name: string; description: string; smartAddress: Address; - eligibility?: `0x${string}`; + eligibility?: Address; payments?: SablierPayment[]; } @@ -51,7 +51,7 @@ interface RolesStoreData { export interface DecentRoleHat extends DecentHat { wearer: Address; - eligibility?: `0x${string}`; + eligibility?: Address; roleTerms: { nominee: Address; termEndDate: Date; termNumber: number }[]; isTermed: boolean; } From dbffd048c472cfdd266f3ecec402bd08bf2ca631 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:51:29 -0400 Subject: [PATCH 039/191] add todo --- src/providers/NetworkConfig/networks/sepolia.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/providers/NetworkConfig/networks/sepolia.ts b/src/providers/NetworkConfig/networks/sepolia.ts index 8cedb11bb2..cc5c1b7bf4 100644 --- a/src/providers/NetworkConfig/networks/sepolia.ts +++ b/src/providers/NetworkConfig/networks/sepolia.ts @@ -80,6 +80,7 @@ export const sepoliaConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), + // @todo update addresses when contracts are deployed decentHatsMasterCopy: getAddress('0xb588Af5A2C5725caee72Be9DC6C776c8b5527915'), decentAutonomousAdminMasterCopy: getAddress('0xCF9F5A1AD7dFFEE35a23d48848CD1Bc0Ccb6F74a'), decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), From 6d23fb5853ce44725e14a9ca1528503b78cbfac5 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:52:39 -0400 Subject: [PATCH 040/191] update copy --- src/i18n/locales/en/roles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/locales/en/roles.json b/src/i18n/locales/en/roles.json index 4cec43d2c9..48577fe8a3 100644 --- a/src/i18n/locales/en/roles.json +++ b/src/i18n/locales/en/roles.json @@ -88,7 +88,7 @@ "cancelPayment": "Cancel Payment", "cancelled": "Canceled", "cancelling": "Cancelling", - "cancelPaymentInfoMessage": "These values can’t be edited. To update them, please cancel this payment and create a new one.", + "cancelPaymentInfoMessage": "These values can't be edited. To update them, please cancel this payment and create a new one.", "cancellingPaymentInfoMessage": "This payment is marked for cancelling and thus can not be edited.", "confirmCancelPaymentTitle": "Are you sure you want to cancel this payment?", "confirmCancelPaymentBody": "This action cannot be undone.", From bafd71a57eb5350438f6c9f2eba2cd7b21420f82 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:55:07 -0400 Subject: [PATCH 041/191] revert change to vite package version --- package-lock.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88cf6ec4c8..3f8b3dfeb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "remark-gfm": "^4.0.0", "sonner": "^1.5.0", "viem": "^2.13.1", - "vite": "5.3.4", + "vite": "^5.3.4", "vite-plugin-checker": "^0.6.4", "wagmi": "^2.12.12", "yup": "^1.4.0", diff --git a/package.json b/package.json index 985ef9a39a..32fce84883 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "remark-gfm": "^4.0.0", "sonner": "^1.5.0", "viem": "^2.13.1", - "vite": "5.3.4", + "vite": "^5.3.4", "vite-plugin-checker": "^0.6.4", "wagmi": "^2.12.12", "yup": "^1.4.0", @@ -127,4 +127,4 @@ "url": "^0.11.0", "vitest": "^1.2.2" } -} +} \ No newline at end of file From ec55f76966210e67ccab34f4558ce78ad2b47c28 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Tue, 22 Oct 2024 01:19:23 -0400 Subject: [PATCH 042/191] hide close X if first term --- src/components/pages/Roles/forms/RoleFormTerms.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/pages/Roles/forms/RoleFormTerms.tsx b/src/components/pages/Roles/forms/RoleFormTerms.tsx index 0a6fe28d2a..91b8d8f700 100644 --- a/src/components/pages/Roles/forms/RoleFormTerms.tsx +++ b/src/components/pages/Roles/forms/RoleFormTerms.tsx @@ -105,11 +105,13 @@ function RoleTermCreate({ w="full" > {t('termNumber', { number: termIndex + 1 })} +