diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9282e82..1681e78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,10 @@ name: test -on: workflow_dispatch +on: + push: + branches: + - "**" # This will match pushes to all branches + workflow_dispatch: env: FOUNDRY_PROFILE: ci diff --git a/.gitignore b/.gitignore index 052b88b..6139161 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ docs/ # Soldeer /dependencies +node_modules/ \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index eed5fdd..86cf7c9 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,5 +3,8 @@ src = "src" out = "out" libs = ["lib"] remappings = ["forge-std/=lib/forge-std/src/"] - -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options +ffi = true +ast = true +build_info = true +extra_output = ["storageLayout"] +gas_reports = ["MagicSpendStakeManager", "MagicSpendWithdrawalManager"] diff --git a/package.json b/package.json new file mode 100644 index 0000000..35cfc1f --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "magic-spend", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@openzeppelin/upgrades-core": "^1.40.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..11c27a1 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,588 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@openzeppelin/upgrades-core': + specifier: ^1.40.0 + version: 1.40.0 + +packages: + + '@nomicfoundation/slang-darwin-arm64@0.17.0': + resolution: {integrity: sha512-O0q94EUtoWy9A5kOTOa9/khtxXDYnLqmuda9pQELurSiwbQEVCPQL8kb34VbOW+ifdre66JM/05Xw9JWhIZ9sA==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-darwin-x64@0.17.0': + resolution: {integrity: sha512-IaDbHzvT08sBK2HyGzonWhq1uu8IxdjmTqAWHr25Oh/PYnamdi8u4qchZXXYKz/DHLoYN3vIpBXoqLQIomhD/g==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-arm64-gnu@0.17.0': + resolution: {integrity: sha512-Lj4anvOsQZxs1SycG8VyT2Rl2oqIhyLSUCgGepTt3CiJ/bM+8r8bLJIgh8vKkki4BWz49YsYIgaJB2IPv8FFTw==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-arm64-musl@0.17.0': + resolution: {integrity: sha512-/xkTCa9d5SIWUBQE3BmLqDFfJRr4yUBwbl4ynPiGUpRXrD69cs6pWKkwjwz/FdBpXqVo36I+zY95qzoTj/YhOA==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-x64-gnu@0.17.0': + resolution: {integrity: sha512-oe5IO5vntOqYvTd67deCHPIWuSuWm6aYtT2/0Kqz2/VLtGz4ClEulBSRwfnNzBVtw2nksWipE1w8BzhImI7Syg==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-x64-musl@0.17.0': + resolution: {integrity: sha512-PpYCI5K/kgLAMXaPY0V4VST5gCDprEOh7z/47tbI8kJQumI5odjsj/Cs8MpTo7/uRH6flKYbVNgUzcocWVYrAQ==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-win32-arm64-msvc@0.17.0': + resolution: {integrity: sha512-u/Mkf7OjokdBilP7QOJj6QYJU4/mjkbKnTX21wLyCIzeVWS7yafRPYpBycKIBj2pRRZ6ceAY5EqRpb0aiCq+0Q==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-win32-ia32-msvc@0.17.0': + resolution: {integrity: sha512-XJBVQfNnZQUv0tP2JSJ573S+pmgrLWgqSZOGaMllnB/TL1gRci4Z7dYRJUF2s82GlRJE+FHSI2Ro6JISKmlXCg==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-win32-x64-msvc@0.17.0': + resolution: {integrity: sha512-zPGsAeiTfqfPNYHD8BfrahQmYzA78ZraoHKTGraq/1xwJwzBK4bu/NtvVA4pJjBV+B4L6DCxVhSbpn40q26JQA==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang@0.17.0': + resolution: {integrity: sha512-1GlkGRcGpVnjFw9Z1vvDKOKo2mzparFt7qrl2pDxWp+jrVtlvej98yCMX52pVyrYE7ZeOSZFnx/DtsSgoukStQ==} + engines: {node: '>= 10'} + + '@openzeppelin/upgrades-core@1.40.0': + resolution: {integrity: sha512-4bPSXdEqHsNRL5T1ybPLneWGYjzGl6XWGWkv7aUoFFgz8mOdarstRBX1Wi4XJFw6IeHPUI7mMSQr2jdz8Y2ypQ==} + hasBin: true + + '@types/bn.js@5.1.6': + resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} + + '@types/node@22.9.0': + resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + + '@types/pbkdf2@3.1.2': + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + + '@types/secp256k1@4.0.6': + resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.10: + resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + cbor@9.0.2: + resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==} + engines: {node: '>=16'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + elliptic@6.6.0: + resolution: {integrity: sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==} + + ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + + ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + + node-addon-api@5.1.0: + resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + + node-gyp-build@4.8.2: + resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} + hasBin: true + + nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + + pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + + rlp@2.2.7: + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + secp256k1@4.0.4: + resolution: {integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==} + engines: {node: '>=18.0.0'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + solidity-ast@0.4.59: + resolution: {integrity: sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + +snapshots: + + '@nomicfoundation/slang-darwin-arm64@0.17.0': {} + + '@nomicfoundation/slang-darwin-x64@0.17.0': {} + + '@nomicfoundation/slang-linux-arm64-gnu@0.17.0': {} + + '@nomicfoundation/slang-linux-arm64-musl@0.17.0': {} + + '@nomicfoundation/slang-linux-x64-gnu@0.17.0': {} + + '@nomicfoundation/slang-linux-x64-musl@0.17.0': {} + + '@nomicfoundation/slang-win32-arm64-msvc@0.17.0': {} + + '@nomicfoundation/slang-win32-ia32-msvc@0.17.0': {} + + '@nomicfoundation/slang-win32-x64-msvc@0.17.0': {} + + '@nomicfoundation/slang@0.17.0': + dependencies: + '@nomicfoundation/slang-darwin-arm64': 0.17.0 + '@nomicfoundation/slang-darwin-x64': 0.17.0 + '@nomicfoundation/slang-linux-arm64-gnu': 0.17.0 + '@nomicfoundation/slang-linux-arm64-musl': 0.17.0 + '@nomicfoundation/slang-linux-x64-gnu': 0.17.0 + '@nomicfoundation/slang-linux-x64-musl': 0.17.0 + '@nomicfoundation/slang-win32-arm64-msvc': 0.17.0 + '@nomicfoundation/slang-win32-ia32-msvc': 0.17.0 + '@nomicfoundation/slang-win32-x64-msvc': 0.17.0 + + '@openzeppelin/upgrades-core@1.40.0': + dependencies: + '@nomicfoundation/slang': 0.17.0 + cbor: 9.0.2 + chalk: 4.1.2 + compare-versions: 6.1.1 + debug: 4.3.7 + ethereumjs-util: 7.1.5 + minimatch: 9.0.5 + minimist: 1.2.8 + proper-lockfile: 4.1.2 + solidity-ast: 0.4.59 + transitivePeerDependencies: + - supports-color + + '@types/bn.js@5.1.6': + dependencies: + '@types/node': 22.9.0 + + '@types/node@22.9.0': + dependencies: + undici-types: 6.19.8 + + '@types/pbkdf2@3.1.2': + dependencies: + '@types/node': 22.9.0 + + '@types/secp256k1@4.0.6': + dependencies: + '@types/node': 22.9.0 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + balanced-match@1.0.2: {} + + base-x@3.0.10: + dependencies: + safe-buffer: 5.2.1 + + blakejs@1.2.1: {} + + bn.js@4.12.0: {} + + bn.js@5.2.1: {} + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + brorand@1.1.0: {} + + browserify-aes@1.2.0: + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + bs58@4.0.1: + dependencies: + base-x: 3.0.10 + + bs58check@2.1.2: + dependencies: + bs58: 4.0.1 + create-hash: 1.2.0 + safe-buffer: 5.2.1 + + buffer-xor@1.0.3: {} + + cbor@9.0.2: + dependencies: + nofilter: 3.1.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + cipher-base@1.0.4: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + compare-versions@6.1.1: {} + + create-hash@1.2.0: + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + + create-hmac@1.1.7: + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + elliptic@6.6.0: + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + ethereum-cryptography@0.1.3: + dependencies: + '@types/pbkdf2': 3.1.2 + '@types/secp256k1': 4.0.6 + blakejs: 1.2.1 + browserify-aes: 1.2.0 + bs58check: 2.1.2 + create-hash: 1.2.0 + create-hmac: 1.1.7 + hash.js: 1.1.7 + keccak: 3.0.4 + pbkdf2: 3.1.2 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + scrypt-js: 3.0.1 + secp256k1: 4.0.4 + setimmediate: 1.0.5 + + ethereumjs-util@7.1.5: + dependencies: + '@types/bn.js': 5.1.6 + bn.js: 5.2.1 + create-hash: 1.2.0 + ethereum-cryptography: 0.1.3 + rlp: 2.2.7 + + evp_bytestokey@1.0.3: + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hash-base@3.1.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + inherits@2.0.4: {} + + keccak@3.0.4: + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.8.2 + readable-stream: 3.6.2 + + md5.js@1.3.5: + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + node-addon-api@2.0.2: {} + + node-addon-api@5.1.0: {} + + node-gyp-build@4.8.2: {} + + nofilter@3.1.0: {} + + pbkdf2@3.1.2: + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + retry@0.12.0: {} + + ripemd160@2.0.2: + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + + rlp@2.2.7: + dependencies: + bn.js: 5.2.1 + + safe-buffer@5.2.1: {} + + scrypt-js@3.0.1: {} + + secp256k1@4.0.4: + dependencies: + elliptic: 6.6.0 + node-addon-api: 5.1.0 + node-gyp-build: 4.8.2 + + setimmediate@1.0.5: {} + + sha.js@2.4.11: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + signal-exit@3.0.7: {} + + solidity-ast@0.4.59: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + undici-types@6.19.8: {} + + util-deprecate@1.0.2: {} diff --git a/remappings.txt b/remappings.txt index 609e22b..0caa593 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,5 +1,6 @@ @openzeppelin-5.0.2/contracts/=lib/openzeppelin-contracts-upgradeable-v5.0.2/lib/openzeppelin-contracts/contracts/ @openzeppelin-5.0.2/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable-v5.0.2/contracts/ +@openzeppelin-0.3.6/foundry-upgrades/=lib/openzeppelin-foundry-upgrades-v0.3.6/src/ @solady-0.0.259/=lib/solady-v0.0.259/src/ forge-std-1.9.3/=dependencies/forge-std-1.9.3/ diff --git a/script/MagicSpend.s.sol b/script/MagicSpend.s.sol index 3515581..3129b30 100644 --- a/script/MagicSpend.s.sol +++ b/script/MagicSpend.s.sol @@ -1,34 +1,34 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "forge-std/Script.sol"; -import {MagicSpendStakeManager} from "./../src/MagicSpendStakeManager.sol"; -import {MagicSpendWithdrawalManager} from "./../src/MagicSpendWithdrawalManager.sol"; -import {ETH} from "./../src/base/Helpers.sol"; +// import "forge-std/Script.sol"; +// import {MagicSpendStakeManager} from "./../src/MagicSpendStakeManager.sol"; +// import {MagicSpendWithdrawalManager} from "./../src/MagicSpendWithdrawalManager.sol"; +// import {ETH} from "./../src/base/Helpers.sol"; -contract MagicSpend_Deploy is Script { - function setUp() public {} +// contract MagicSpend_Deploy is Script { +// function setUp() public {} - function run() public returns (address _stakeManager, address _withdrawalManager) { - address deployer = vm.rememberKey(vm.envUint("DEPLOYER")); - address owner = vm.rememberKey(vm.envUint("OWNER")); - address signer = vm.rememberKey(vm.envUint("SIGNER")); - address alice = vm.rememberKey(vm.envUint("ALICE")); +// function run() public returns (address _stakeManager, address _withdrawalManager) { +// address deployer = vm.rememberKey(vm.envUint("DEPLOYER")); +// address owner = vm.rememberKey(vm.envUint("OWNER")); +// address signer = vm.rememberKey(vm.envUint("SIGNER")); +// address alice = vm.rememberKey(vm.envUint("ALICE")); - bytes32 salt = vm.envBytes32("SALT"); +// bytes32 salt = vm.envBytes32("SALT"); - vm.startBroadcast(deployer); - MagicSpendStakeManager stakeManager = new MagicSpendStakeManager{salt: salt}(owner); +// vm.startBroadcast(deployer); +// MagicSpendStakeManager stakeManager = new MagicSpendStakeManager{salt: salt}(owner); - MagicSpendWithdrawalManager withdrawalManager = new MagicSpendWithdrawalManager{salt: salt}(owner, signer); +// MagicSpendWithdrawalManager withdrawalManager = new MagicSpendWithdrawalManager{salt: salt}(owner, signer); - withdrawalManager.addLiquidity{value: 0.01 ether}(ETH, 0.01 ether); - vm.stopBroadcast(); +// withdrawalManager.addLiquidity{value: 0.01 ether}(ETH, 0.01 ether); +// vm.stopBroadcast(); - vm.startBroadcast(alice); - stakeManager.addStake{value: 0.01 ether}(ETH, 0.01 ether, 86400); - vm.stopBroadcast(); +// vm.startBroadcast(alice); +// stakeManager.addStake{value: 0.01 ether}(ETH, 0.01 ether, 86400); +// vm.stopBroadcast(); - return (address(stakeManager), address(withdrawalManager)); - } -} +// return (address(stakeManager), address(withdrawalManager)); +// } +// } diff --git a/src/MagicSpendStakeManager.sol b/src/MagicSpendStakeManager.sol index bba17d3..2060e1f 100644 --- a/src/MagicSpendStakeManager.sol +++ b/src/MagicSpendStakeManager.sol @@ -5,10 +5,9 @@ import {IERC20} from "@openzeppelin-5.0.2/contracts/token/ERC20/IERC20.sol"; import {ECDSA} from "@openzeppelin-5.0.2/contracts/utils/cryptography/ECDSA.sol"; import {MessageHashUtils} from "@openzeppelin-5.0.2/contracts/utils/cryptography/MessageHashUtils.sol"; import {Math} from "@openzeppelin-5.0.2/contracts/utils/math/Math.sol"; -import {Ownable} from "@openzeppelin-5.0.2/contracts/access/Ownable.sol"; import {SignatureChecker} from "@openzeppelin-5.0.2/contracts/utils/cryptography/SignatureChecker.sol"; -import {EIP712} from "@openzeppelin-5.0.2/contracts/utils/cryptography/EIP712.sol"; - +import {EIP712Upgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {StakeManager} from "./base/StakeManager.sol"; import {ETH, ClaimRequest, ClaimStruct} from "./base/Helpers.sol"; @@ -17,9 +16,8 @@ import {SafeTransferLib} from "@solady-0.0.259/utils/SafeTransferLib.sol"; /// @title MagicSpendStakeManager /// @author Pimlico (https://github.com/pimlicolabs/magic-spend) /// @notice Contract that allows users to stake their funds. -/// @dev Inherits from Ownable. /// @custom:security-contact security@pimlico.io -contract MagicSpendStakeManager is Ownable, StakeManager, EIP712 { +contract MagicSpendStakeManager is StakeManager, OwnableUpgradeable, EIP712Upgradeable { bytes32 private constant CLAIM_STRUCT_TYPE_HASH = keccak256("ClaimStruct(address asset,uint128 amount,uint128 fee,uint128 chainId)"); @@ -58,7 +56,12 @@ contract MagicSpendStakeManager is Ownable, StakeManager, EIP712 { mapping(bytes32 hash_ => bool) public requestStatuses; mapping(address asset => uint128) public claimed; - constructor(address _owner) Ownable(_owner) EIP712("Pimlico Magic Spend", "1") {} + function initialize( + address _owner + ) external initializer { + __Ownable_init(_owner); + __EIP712_init("Pimlico Magic Spend", "1"); + } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ diff --git a/src/MagicSpendWithdrawalManager.sol b/src/MagicSpendWithdrawalManager.sol index 2102ef7..1cb66c0 100644 --- a/src/MagicSpendWithdrawalManager.sol +++ b/src/MagicSpendWithdrawalManager.sol @@ -5,25 +5,23 @@ import {IERC20} from "@openzeppelin-5.0.2/contracts/token/ERC20/IERC20.sol"; import {ECDSA} from "@openzeppelin-5.0.2/contracts/utils/cryptography/ECDSA.sol"; import {MessageHashUtils} from "@openzeppelin-5.0.2/contracts/utils/cryptography/MessageHashUtils.sol"; import {Math} from "@openzeppelin-5.0.2/contracts/utils/math/Math.sol"; -import {Ownable} from "@openzeppelin-5.0.2/contracts/access/Ownable.sol"; -import {ReentrancyGuard} from "@openzeppelin-5.0.2/contracts/utils/ReentrancyGuard.sol"; +import {OwnableUpgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {SignatureChecker} from "@openzeppelin-5.0.2/contracts/utils/cryptography/SignatureChecker.sol"; -import {EIP712} from "@openzeppelin-5.0.2/contracts/utils/cryptography/EIP712.sol"; - +import {EIP712Upgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; +import {Initializable} from "@openzeppelin-5.0.2/contracts-upgradeable/proxy/utils/Initializable.sol"; import {Signer} from "./base/Signer.sol"; import {WithdrawalManager} from "./base/WithdrawalManager.sol"; import {ETH, WithdrawRequest, CallStruct} from "./base/Helpers.sol"; import {SafeTransferLib} from "@solady-0.0.259/utils/SafeTransferLib.sol"; -import {console} from "forge-std/Test.sol"; /// @title MagicSpendWithdrawalManager /// @author Pimlico (https://github.com/pimlicolabs/magic-spend) /// @notice Contract that allows users to pull funds from if they provide a valid signed request. /// @dev Inherits from Ownable. /// @custom:security-contact security@pimlico.io -contract MagicSpendWithdrawalManager is Ownable, Signer, WithdrawalManager, EIP712 { +contract MagicSpendWithdrawalManager is OwnableUpgradeable, Signer, WithdrawalManager, EIP712Upgradeable { bytes32 private constant CALL_STRUCT_TYPE_HASH = keccak256("CallStruct(address to,uint256 value,bytes data)"); bytes32 private constant WITHDRAW_REQUEST_TYPE_HASH = keccak256( @@ -59,7 +57,12 @@ contract MagicSpendWithdrawalManager is Ownable, Signer, WithdrawalManager, EIP7 mapping(bytes32 hash_ => bool) public requestStatuses; - constructor(address _owner, address _signer) Ownable(_owner) EIP712("Pimlico Magic Spend", "1") Signer(_signer) {} + // constructor(address _owner, address _signer) Ownable(_owner) EIP712("Pimlico Magic Spend", "1") Signer(_signer) {} + function initialize(address _owner, address _signer) external initializer { + __Ownable_init(_owner); + __EIP712_init("Pimlico Magic Spend", "1"); + __Signer_init(_signer); + } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ @@ -84,9 +87,6 @@ contract MagicSpendWithdrawalManager is Ownable, Signer, WithdrawalManager, EIP7 bytes32 hash_ = getWithdrawRequestHash(request); - console.log("liquidity-manager.hash"); - console.logBytes32(hash_); - bool signatureValid = SignatureChecker.isValidSignatureNow(getSigner(), hash_, signature); if (!signatureValid) { diff --git a/src/base/Signer.sol b/src/base/Signer.sol index 8531eb5..18f9305 100644 --- a/src/base/Signer.sol +++ b/src/base/Signer.sol @@ -3,13 +3,12 @@ pragma solidity ^0.8.0; /* solhint-disable reason-string */ -import {Ownable} from "@openzeppelin-5.0.2/contracts/access/Ownable.sol"; -import {IERC165} from "@openzeppelin-5.0.2/contracts/utils/introspection/IERC165.sol"; +import {OwnableUpgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * Helper class for creating a contract with signer. */ -abstract contract Signer is Ownable { +abstract contract Signer is OwnableUpgradeable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ @@ -24,11 +23,7 @@ abstract contract Signer is Ownable { /// @notice Signer address. address private signer; - /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ - /* CONSTRUCTOR */ - /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - - constructor(address _signer) { + function __Signer_init(address _signer) internal { _addSigner(_signer); } diff --git a/src/base/StakeManager.sol b/src/base/StakeManager.sol index 57321a4..eb06cd6 100644 --- a/src/base/StakeManager.sol +++ b/src/base/StakeManager.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {SafeTransferLib} from "@solady-0.0.259/utils/SafeTransferLib.sol"; -import {ReentrancyGuard} from "@openzeppelin-5.0.2/contracts/utils/ReentrancyGuard.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {ETH} from "./Helpers.sol"; /* solhint-disable avoid-low-level-calls */ @@ -16,7 +16,7 @@ import {ETH} from "./Helpers.sol"; * - Stake is claimed every time `MagicSpendPlusMinusHalf.claim` is called * - To remove stake, call `removeStake` with the asset and recipient. No partical unstakes are allowed. */ -abstract contract StakeManager is ReentrancyGuard { +abstract contract StakeManager is ReentrancyGuardUpgradeable { error InvalidUnstakeDelay(); error StakeTooLow(); error StakeTooHigh(); diff --git a/src/base/WithdrawalManager.sol b/src/base/WithdrawalManager.sol index dc4ac05..7416ca0 100644 --- a/src/base/WithdrawalManager.sol +++ b/src/base/WithdrawalManager.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; import {SafeTransferLib} from "@solady-0.0.259/utils/SafeTransferLib.sol"; -import {Ownable} from "@openzeppelin-5.0.2/contracts/access/Ownable.sol"; -import {ReentrancyGuard} from "@openzeppelin-5.0.2/contracts/utils/ReentrancyGuard.sol"; +import {OwnableUpgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-5.0.2/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {ETH} from "./Helpers.sol"; -abstract contract WithdrawalManager is Ownable, ReentrancyGuard { +abstract contract WithdrawalManager is OwnableUpgradeable, ReentrancyGuardUpgradeable { event LiquidityAdded(address asset, uint128 amount); event LiquidityRemoved(address asset, uint128 amount); diff --git a/test/MagicSpendStakeManager.t.sol b/test/MagicSpendStakeManager.t.sol index 160877c..45d24aa 100644 --- a/test/MagicSpendStakeManager.t.sol +++ b/test/MagicSpendStakeManager.t.sol @@ -12,6 +12,8 @@ import {MessageHashUtils} from "@openzeppelin-5.0.2/contracts/utils/cryptography import {SafeTransferLib} from "@solady-0.0.259/utils/SafeTransferLib.sol"; import {MagicSpendStakeManager} from "./../src/MagicSpendStakeManager.sol"; +import {Upgrades} from "@openzeppelin-0.3.6/foundry-upgrades/Upgrades.sol"; + contract MagicSpendStakeManagerTest is Test { address immutable OWNER = makeAddr("owner"); address immutable RECIPIENT = makeAddr("recipient"); @@ -30,7 +32,13 @@ contract MagicSpendStakeManagerTest is Test { function setUp() external { (alice, aliceKey) = makeAddrAndKey("alice"); - magicSpendStakeManager = new MagicSpendStakeManager(OWNER); + address proxy = Upgrades.deployTransparentProxy( + "MagicSpendStakeManager.sol", + OWNER, + abi.encodeCall(MagicSpendStakeManager.initialize, (OWNER)) + ); + + magicSpendStakeManager = MagicSpendStakeManager(payable(proxy)); token = new TestERC20(18); forceReverter = new ForceReverter(); diff --git a/test/MagicSpendWithdrawalManager.t.sol b/test/MagicSpendWithdrawalManager.t.sol index dd06fbf..51e5adc 100644 --- a/test/MagicSpendWithdrawalManager.t.sol +++ b/test/MagicSpendWithdrawalManager.t.sol @@ -12,6 +12,8 @@ import {MessageHashUtils} from "@openzeppelin-5.0.2/contracts/utils/cryptography import {SafeTransferLib} from "@solady-0.0.259/utils/SafeTransferLib.sol"; import {MagicSpendWithdrawalManager} from "./../src/MagicSpendWithdrawalManager.sol"; +import {Upgrades} from "@openzeppelin-0.3.6/foundry-upgrades/Upgrades.sol"; + contract MagicSpendLiquidityManagerTest is Test { address immutable OWNER = makeAddr("owner"); address immutable RECIPIENT = makeAddr("recipient"); @@ -30,7 +32,13 @@ contract MagicSpendLiquidityManagerTest is Test { function setUp() external { (signer, signerKey) = makeAddrAndKey("signer"); - magicSpendWithdrawalManager = new MagicSpendWithdrawalManager(OWNER, signer); + address proxy = Upgrades.deployTransparentProxy( + "MagicSpendWithdrawalManager.sol", + OWNER, + abi.encodeCall(MagicSpendWithdrawalManager.initialize, (OWNER, signer)) + ); + + magicSpendWithdrawalManager = MagicSpendWithdrawalManager(payable(proxy)); token = new TestERC20(18); forceReverter = new ForceReverter();