From 0638a2e1fce281db9ffb36acc43f14f250d179fc Mon Sep 17 00:00:00 2001 From: David Huber Date: Thu, 22 Jan 2026 17:41:58 +0200 Subject: [PATCH 1/2] Update to permit v3 --- package.json | 6 +- pnpm-lock.yaml | 37 +- src/ExampleSaleABI.ts | 711 +++++++++------------------ src/components/sale/PurchaseCard.tsx | 6 +- src/hooks.ts | 10 +- 5 files changed, 258 insertions(+), 512 deletions(-) diff --git a/package.json b/package.json index 547489e..fdab7b9 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "lint": "eslint" }, "dependencies": { - "@echoxyz/sonar-core": "^0.12.0", - "@echoxyz/sonar-react": "^0.12.0", + "@echoxyz/sonar-core": "^0.13.0", + "@echoxyz/sonar-react": "^0.12.2", "@tanstack/react-query": "^5.90.12", "connectkit": "^1.9.1", "react": "^18.3.1", @@ -20,11 +20,11 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.3.3", + "@eslint/js": "^9.39.2", "@tailwindcss/postcss": "^4", "@types/react": "^18", "@types/react-dom": "^18", "@vitejs/plugin-react": "^4.3.4", - "@eslint/js": "^9.39.2", "eslint": "^9.39.2", "globals": "^17.0.0", "tailwindcss": "^4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8681972..c34926d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: dependencies: '@echoxyz/sonar-core': - specifier: ^0.12.0 - version: 0.12.0 + specifier: ^0.13.0 + version: 0.13.0 '@echoxyz/sonar-react': - specifier: ^0.12.0 - version: 0.12.1(react@18.3.1) + specifier: ^0.12.2 + version: 0.12.2(react@18.3.1) '@tanstack/react-query': specifier: ^5.90.12 version: 5.90.16(react@18.3.1) @@ -269,11 +269,11 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@echoxyz/sonar-core@0.12.0': - resolution: {integrity: sha512-K3/Xa6vy27AkIHV8bO4Y2/GaWdYTtfWEf/j4BWo5S00QdjR6IyzFLmPFLsxFznQSMBCqsusmRXD8XBVqqOJwXw==} + '@echoxyz/sonar-core@0.13.0': + resolution: {integrity: sha512-JKNzkTxrihiwwnvLrF/Oe3GXkKxRwMlPTStbs41gZg7eWBJ0EfgzSLJMFNNjO+PRbgvTbStavoLvQ7BHx1ljuQ==} - '@echoxyz/sonar-react@0.12.1': - resolution: {integrity: sha512-sawBc0Gexz2XkG/7PbPZtG/EIGEFIkL4ultijdnNipl33Txd/fgEAwSTqg/JmPcgrkJAYJ+SiM0GzPZ1FWpkww==} + '@echoxyz/sonar-react@0.12.2': + resolution: {integrity: sha512-iuQQrAFiNMsH+NRvaSQvGFsAiYJRQHTDYO774uENkJGsZPtP39JYRhqXw3PCY0cr4CzuCURu0fqaQx7aAl1Xrg==} peerDependencies: react: '>=18' @@ -2415,6 +2415,9 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -3235,8 +3238,8 @@ packages: preact@10.24.2: resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} - preact@10.28.1: - resolution: {integrity: sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==} + preact@10.28.2: + resolution: {integrity: sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -4284,9 +4287,9 @@ snapshots: clsx: 1.2.1 eth-block-tracker: 7.1.0 eth-json-rpc-filters: 6.0.1 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 keccak: 3.0.4 - preact: 10.28.1 + preact: 10.28.2 sha.js: 2.4.12 transitivePeerDependencies: - supports-color @@ -4333,11 +4336,11 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} - '@echoxyz/sonar-core@0.12.0': {} + '@echoxyz/sonar-core@0.13.0': {} - '@echoxyz/sonar-react@0.12.1(react@18.3.1)': + '@echoxyz/sonar-react@0.12.2(react@18.3.1)': dependencies: - '@echoxyz/sonar-core': 0.12.0 + '@echoxyz/sonar-core': 0.13.0 react: 18.3.1 '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': @@ -7346,6 +7349,8 @@ snapshots: eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} + events@3.3.0: {} expect-type@1.3.0: {} @@ -8140,7 +8145,7 @@ snapshots: preact@10.24.2: {} - preact@10.28.1: {} + preact@10.28.2: {} prelude-ls@1.2.1: {} diff --git a/src/ExampleSaleABI.ts b/src/ExampleSaleABI.ts index 26162f6..0a96343 100644 --- a/src/ExampleSaleABI.ts +++ b/src/ExampleSaleABI.ts @@ -1,604 +1,343 @@ export const examplSaleABI = [ { + type: "constructor", inputs: [ { - components: [ - { - internalType: "bytes16", - name: "saleUUID", - type: "bytes16", - }, - { - internalType: "address", - name: "purchasePermitSigner", - type: "address", - }, - ], - internalType: "struct ExampleSale.Init", name: "init", type: "tuple", + internalType: "struct ExampleSale.Init", + components: [ + { name: "saleUUID", type: "bytes16", internalType: "bytes16" }, + { name: "purchasePermitSigner", type: "address", internalType: "address" }, + ], }, ], stateMutability: "nonpayable", - type: "constructor", }, { + type: "function", + name: "DEFAULT_ADMIN_ROLE", inputs: [], - name: "AccessControlBadConfirmation", - type: "error", + outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - { - internalType: "bytes32", - name: "neededRole", - type: "bytes32", - }, - ], - name: "AccessControlUnauthorizedAccount", - type: "error", + type: "function", + name: "MAX_ADDRESSES_PER_ENTITY", + inputs: [], + outputs: [{ name: "", type: "uint8", internalType: "uint8" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "address", - name: "addr", - type: "address", - }, - { - internalType: "bytes16", - name: "got", - type: "bytes16", - }, - { - internalType: "bytes16", - name: "existing", - type: "bytes16", - }, - ], - name: "AddressTiedToAnotherEntity", - type: "error", + type: "function", + name: "PURCHASE_PERMIT_SIGNER_ROLE", + inputs: [], + outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - internalType: "uint256", - name: "minAmount", - type: "uint256", - }, - ], - name: "AmountBelowMinimum", - type: "error", + type: "function", + name: "amountByAddress", + inputs: [{ name: "", type: "address", internalType: "address" }], + outputs: [{ name: "", type: "uint256", internalType: "uint256" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - internalType: "uint256", - name: "maxAmount", - type: "uint256", - }, - ], - name: "AmountExceedsMaximum", - type: "error", + type: "function", + name: "amountByEntity", + inputs: [{ name: "", type: "bytes16", internalType: "bytes16" }], + outputs: [{ name: "", type: "uint256", internalType: "uint256" }], + stateMutability: "view", }, { - inputs: [], - name: "ECDSAInvalidSignature", - type: "error", + type: "function", + name: "entityByAddress", + inputs: [{ name: "addr", type: "address", internalType: "address" }], + outputs: [{ name: "", type: "bytes16", internalType: "bytes16" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "uint256", - name: "length", - type: "uint256", - }, - ], - name: "ECDSAInvalidSignatureLength", - type: "error", + type: "function", + name: "entityIDByAddress", + inputs: [{ name: "", type: "address", internalType: "address" }], + outputs: [{ name: "", type: "bytes16", internalType: "bytes16" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "bytes32", - name: "s", - type: "bytes32", - }, - ], - name: "ECDSAInvalidSignatureS", - type: "error", + type: "function", + name: "getEntityAddressCount", + inputs: [{ name: "entityID", type: "bytes16", internalType: "bytes16" }], + outputs: [{ name: "", type: "uint256", internalType: "uint256" }], + stateMutability: "view", }, { - inputs: [], - name: "PurchasePermitExpired", - type: "error", + type: "function", + name: "getEntityAddresses", + inputs: [{ name: "entityID", type: "bytes16", internalType: "bytes16" }], + outputs: [{ name: "", type: "address[]", internalType: "address[]" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "bytes16", - name: "got", - type: "bytes16", - }, + type: "function", + name: "getEntityPurchaseBreakdown", + inputs: [{ name: "entityID", type: "bytes16", internalType: "bytes16" }], + outputs: [ { - internalType: "bytes16", - name: "want", - type: "bytes16", + name: "purchases", + type: "tuple[]", + internalType: "struct ExampleSale.AddressPurchase[]", + components: [ + { name: "addr", type: "address", internalType: "address" }, + { name: "amount", type: "uint256", internalType: "uint256" }, + ], }, ], - name: "PurchasePermitSaleUUIDMismatch", - type: "error", + stateMutability: "view", }, { - inputs: [ - { - internalType: "address", - name: "got", - type: "address", - }, - { - internalType: "address", - name: "want", - type: "address", - }, - ], - name: "PurchasePermitSenderMismatch", - type: "error", + type: "function", + name: "getRoleAdmin", + inputs: [{ name: "role", type: "bytes32", internalType: "bytes32" }], + outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }], + stateMutability: "view", }, { + type: "function", + name: "getRoleMember", inputs: [ - { - internalType: "address", - name: "signer", - type: "address", - }, + { name: "role", type: "bytes32", internalType: "bytes32" }, + { name: "index", type: "uint256", internalType: "uint256" }, ], - name: "PurchasePermitUnauthorizedSigner", - type: "error", + outputs: [{ name: "", type: "address", internalType: "address" }], + stateMutability: "view", }, { - inputs: [], - name: "ZeroAddress", - type: "error", + type: "function", + name: "getRoleMemberCount", + inputs: [{ name: "role", type: "bytes32", internalType: "bytes32" }], + outputs: [{ name: "", type: "uint256", internalType: "uint256" }], + stateMutability: "view", }, { - inputs: [], - name: "ZeroEntityID", - type: "error", + type: "function", + name: "grantRole", + inputs: [ + { name: "role", type: "bytes32", internalType: "bytes32" }, + { name: "account", type: "address", internalType: "address" }, + ], + outputs: [], + stateMutability: "nonpayable", }, { - anonymous: false, + type: "function", + name: "hasRole", inputs: [ - { - indexed: true, - internalType: "address", - name: "wallet", - type: "address", - }, - { - indexed: true, - internalType: "bytes16", - name: "entityID", - type: "bytes16", - }, - { - indexed: false, - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - indexed: false, - internalType: "uint256", - name: "totalAmount", - type: "uint256", - }, + { name: "role", type: "bytes32", internalType: "bytes32" }, + { name: "account", type: "address", internalType: "address" }, ], - name: "Purchased", - type: "event", + outputs: [{ name: "", type: "bool", internalType: "bool" }], + stateMutability: "view", }, { - anonymous: false, + type: "function", + name: "purchase", inputs: [ + { name: "amount", type: "uint256", internalType: "uint256" }, { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "bytes32", - name: "previousAdminRole", - type: "bytes32", - }, - { - indexed: true, - internalType: "bytes32", - name: "newAdminRole", - type: "bytes32", + name: "purchasePermit", + type: "tuple", + internalType: "struct PurchasePermitV3", + components: [ + { name: "saleSpecificEntityID", type: "bytes16", internalType: "bytes16" }, + { name: "saleUUID", type: "bytes16", internalType: "bytes16" }, + { name: "wallet", type: "address", internalType: "address" }, + { name: "expiresAt", type: "uint64", internalType: "uint64" }, + { name: "minAmount", type: "uint256", internalType: "uint256" }, + { name: "maxAmount", type: "uint256", internalType: "uint256" }, + { name: "minPrice", type: "uint64", internalType: "uint64" }, + { name: "maxPrice", type: "uint64", internalType: "uint64" }, + { name: "opensAt", type: "uint64", internalType: "uint64" }, + { name: "closesAt", type: "uint64", internalType: "uint64" }, + { name: "payload", type: "bytes", internalType: "bytes" }, + ], }, + { name: "purchasePermitSignature", type: "bytes", internalType: "bytes" }, ], - name: "RoleAdminChanged", - type: "event", + outputs: [], + stateMutability: "nonpayable", }, { - anonymous: false, + type: "function", + name: "renounceRole", inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "address", - name: "account", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, + { name: "role", type: "bytes32", internalType: "bytes32" }, + { name: "callerConfirmation", type: "address", internalType: "address" }, ], - name: "RoleGranted", - type: "event", + outputs: [], + stateMutability: "nonpayable", }, { - anonymous: false, + type: "function", + name: "reset", + inputs: [{ name: "entityID", type: "bytes16", internalType: "bytes16" }], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "revokeRole", inputs: [ - { - indexed: true, - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - indexed: true, - internalType: "address", - name: "account", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "sender", - type: "address", - }, + { name: "role", type: "bytes32", internalType: "bytes32" }, + { name: "account", type: "address", internalType: "address" }, ], - name: "RoleRevoked", - type: "event", + outputs: [], + stateMutability: "nonpayable", }, { + type: "function", + name: "saleUUID", inputs: [], - name: "DEFAULT_ADMIN_ROLE", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], + outputs: [{ name: "", type: "bytes16", internalType: "bytes16" }], stateMutability: "view", - type: "function", }, { - inputs: [], - name: "PURCHASE_PERMIT_SIGNER_ROLE", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", type: "function", + name: "supportsInterface", + inputs: [{ name: "interfaceId", type: "bytes4", internalType: "bytes4" }], + outputs: [{ name: "", type: "bool", internalType: "bool" }], + stateMutability: "view", }, { - inputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - name: "amountByAddress", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", + type: "event", + name: "EntityReset", + inputs: [{ name: "entityID", type: "bytes16", indexed: true, internalType: "bytes16" }], + anonymous: false, }, { + type: "event", + name: "Purchased", inputs: [ - { - internalType: "address", - name: "", - type: "address", - }, + { name: "addr", type: "address", indexed: true, internalType: "address" }, + { name: "entityID", type: "bytes16", indexed: true, internalType: "bytes16" }, + { name: "amount", type: "uint256", indexed: false, internalType: "uint256" }, + { name: "totalAmount", type: "uint256", indexed: false, internalType: "uint256" }, ], - name: "entityIDByAddress", - outputs: [ - { - internalType: "bytes16", - name: "", - type: "bytes16", - }, - ], - stateMutability: "view", - type: "function", + anonymous: false, }, { + type: "event", + name: "RoleAdminChanged", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - ], - name: "getRoleAdmin", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, + { name: "role", type: "bytes32", indexed: true, internalType: "bytes32" }, + { name: "previousAdminRole", type: "bytes32", indexed: true, internalType: "bytes32" }, + { name: "newAdminRole", type: "bytes32", indexed: true, internalType: "bytes32" }, ], - stateMutability: "view", - type: "function", + anonymous: false, }, { + type: "event", + name: "RoleGranted", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - name: "getRoleMember", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, + { name: "role", type: "bytes32", indexed: true, internalType: "bytes32" }, + { name: "account", type: "address", indexed: true, internalType: "address" }, + { name: "sender", type: "address", indexed: true, internalType: "address" }, ], - stateMutability: "view", - type: "function", + anonymous: false, }, { + type: "event", + name: "RoleRevoked", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - ], - name: "getRoleMemberCount", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, + { name: "role", type: "bytes32", indexed: true, internalType: "bytes32" }, + { name: "account", type: "address", indexed: true, internalType: "address" }, + { name: "sender", type: "address", indexed: true, internalType: "address" }, ], - stateMutability: "view", - type: "function", + anonymous: false, }, + { type: "error", name: "AccessControlBadConfirmation", inputs: [] }, { + type: "error", + name: "AccessControlUnauthorizedAccount", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, + { name: "account", type: "address", internalType: "address" }, + { name: "neededRole", type: "bytes32", internalType: "bytes32" }, ], - name: "grantRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", }, { + type: "error", + name: "AddressTiedToAnotherEntity", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, + { name: "addr", type: "address", internalType: "address" }, + { name: "got", type: "bytes16", internalType: "bytes16" }, + { name: "existing", type: "bytes16", internalType: "bytes16" }, ], - name: "hasRole", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", }, { + type: "error", + name: "AmountBelowMinimum", inputs: [ - { - internalType: "uint256", - name: "amount", - type: "uint256", - }, - { - components: [ - { - internalType: "bytes16", - name: "entityID", - type: "bytes16", - }, - { - internalType: "bytes16", - name: "saleUUID", - type: "bytes16", - }, - { - internalType: "address", - name: "wallet", - type: "address", - }, - { - internalType: "uint64", - name: "expiresAt", - type: "uint64", - }, - { - internalType: "uint256", - name: "minAmount", - type: "uint256", - }, - { - internalType: "uint256", - name: "maxAmount", - type: "uint256", - }, - { - internalType: "uint64", - name: "minPrice", - type: "uint64", - }, - { - internalType: "uint64", - name: "maxPrice", - type: "uint64", - }, - { - internalType: "bytes", - name: "payload", - type: "bytes", - }, - ], - internalType: "struct PurchasePermitV2", - name: "purchasePermit", - type: "tuple", - }, - { - internalType: "bytes", - name: "purchasePermitSignature", - type: "bytes", - }, + { name: "amount", type: "uint256", internalType: "uint256" }, + { name: "minAmount", type: "uint256", internalType: "uint256" }, ], - name: "purchase", - outputs: [], - stateMutability: "nonpayable", - type: "function", }, { + type: "error", + name: "AmountExceedsMaximum", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "callerConfirmation", - type: "address", - }, + { name: "amount", type: "uint256", internalType: "uint256" }, + { name: "maxAmount", type: "uint256", internalType: "uint256" }, ], - name: "renounceRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", }, + { type: "error", name: "ECDSAInvalidSignature", inputs: [] }, { - inputs: [], - name: "reset", - outputs: [], - stateMutability: "nonpayable", - type: "function", + type: "error", + name: "ECDSAInvalidSignatureLength", + inputs: [{ name: "length", type: "uint256", internalType: "uint256" }], + }, + { + type: "error", + name: "ECDSAInvalidSignatureS", + inputs: [{ name: "s", type: "bytes32", internalType: "bytes32" }], }, { + type: "error", + name: "PurchaseOutsideAllowedWindow", inputs: [ - { - internalType: "bytes32", - name: "role", - type: "bytes32", - }, - { - internalType: "address", - name: "account", - type: "address", - }, + { name: "opensAt", type: "uint64", internalType: "uint64" }, + { name: "closesAt", type: "uint64", internalType: "uint64" }, + { name: "currentTime", type: "uint256", internalType: "uint256" }, ], - name: "revokeRole", - outputs: [], - stateMutability: "nonpayable", - type: "function", }, + { type: "error", name: "PurchasePermitExpired", inputs: [] }, { - inputs: [], - name: "saleUUID", - outputs: [ - { - internalType: "bytes16", - name: "", - type: "bytes16", - }, + type: "error", + name: "PurchasePermitSaleUUIDMismatch", + inputs: [ + { name: "got", type: "bytes16", internalType: "bytes16" }, + { name: "want", type: "bytes16", internalType: "bytes16" }, ], - stateMutability: "view", - type: "function", }, { + type: "error", + name: "PurchasePermitSenderMismatch", inputs: [ - { - internalType: "bytes4", - name: "interfaceId", - type: "bytes4", - }, + { name: "got", type: "address", internalType: "address" }, + { name: "want", type: "address", internalType: "address" }, ], - name: "supportsInterface", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, + }, + { + type: "error", + name: "PurchasePermitUnauthorizedSigner", + inputs: [{ name: "signer", type: "address", internalType: "address" }], + }, + { + type: "error", + name: "TooManyAddressesForEntity", + inputs: [ + { name: "entityID", type: "bytes16", internalType: "bytes16" }, + { name: "max", type: "uint256", internalType: "uint256" }, ], - stateMutability: "view", - type: "function", }, + { type: "error", name: "ZeroAddress", inputs: [] }, + { type: "error", name: "ZeroEntityID", inputs: [] }, ] as const; - diff --git a/src/components/sale/PurchaseCard.tsx b/src/components/sale/PurchaseCard.tsx index 0560dce..ee370e6 100644 --- a/src/components/sale/PurchaseCard.tsx +++ b/src/components/sale/PurchaseCard.tsx @@ -40,11 +40,11 @@ function readinessConfig( return warningConfig("The connected wallet is not eligible for this sale. Connect a different wallet."); case PrePurchaseFailureReason.MAX_WALLETS_USED: return warningConfig( - "Maximum number of wallets reached — This entity can’t use the connected wallet. Use a previous wallet." + "Maximum number of wallets reached — This entity can't use the connected wallet. Use a previous wallet." ); - case PrePurchaseFailureReason.NO_RESERVED_ALLOCATION: + case PrePurchaseFailureReason.WALLET_NOT_LINKED: return warningConfig( - "No reserved allocation — The connected wallet doesn’t have a reserved spot for this sale. Connect a different wallet." + "Wallet not linked — The connected wallet is not linked to your entity. Please link it first." ); case PrePurchaseFailureReason.SALE_NOT_ACTIVE: return errorConfig("The sale is not currently active."); diff --git a/src/hooks.ts b/src/hooks.ts index d3900bc..00d9ea2 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -1,4 +1,4 @@ -import { BasicPermitV2, GeneratePurchasePermitResponse } from "@echoxyz/sonar-core"; +import { BasicPermitV3, GeneratePurchasePermitResponse } from "@echoxyz/sonar-core"; import { useCallback, useEffect, useState } from "react"; import { useReadContract, useWriteContract, useWaitForTransactionReceipt } from "wagmi"; import { saleContract } from "./config"; @@ -22,10 +22,10 @@ export const useSaleContract = (walletAddress: `0x${string}`) => { const commitWithPermit = useCallback( async ({ purchasePermitResp, amount }: { purchasePermitResp: GeneratePurchasePermitResponse; amount: bigint }) => { - if (!("MinAmount" in purchasePermitResp.PermitJSON)) { + if (!("OpensAt" in purchasePermitResp.PermitJSON)) { throw new Error("Invalid purchase permit response"); } - const permit = purchasePermitResp.PermitJSON as BasicPermitV2; + const permit = purchasePermitResp.PermitJSON as BasicPermitV3; const { request } = await simulateContract(config, { address: saleContract, @@ -34,7 +34,7 @@ export const useSaleContract = (walletAddress: `0x${string}`) => { args: [ amount, { - entityID: permit.SaleSpecificEntityID, + saleSpecificEntityID: permit.SaleSpecificEntityID, saleUUID: permit.SaleUUID, wallet: permit.Wallet, expiresAt: BigInt(permit.ExpiresAt), @@ -42,6 +42,8 @@ export const useSaleContract = (walletAddress: `0x${string}`) => { maxAmount: BigInt(permit.MaxAmount), minPrice: BigInt(permit.MinPrice), maxPrice: BigInt(permit.MaxPrice), + opensAt: BigInt(permit.OpensAt), + closesAt: BigInt(permit.ClosesAt), payload: permit.Payload, }, purchasePermitResp.Signature, From 94603f366c2ff476cfeda82d248416f233bb48b3 Mon Sep 17 00:00:00 2001 From: David Huber Date: Thu, 22 Jan 2026 17:42:32 +0200 Subject: [PATCH 2/2] add env file --- .env.local | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .env.local diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..b3b54db --- /dev/null +++ b/.env.local @@ -0,0 +1,10 @@ +# Change this to match your Sonar sale credentials +# You can find these UUIDs under the integration tab on your Sonar sale dashboard +VITE_SALE_UUID=c0aabe68-c46a-4f20-8780-05ea0e039821 +VITE_OAUTH_CLIENT_UUID=f1f02e3d-c193-4438-b5fb-a27ef2f3a268 + +# Must match a redirect URI configured for your sale's oauth client on the Sonar founder dashboard +VITE_OAUTH_CLIENT_REDIRECT_URI=http://localhost:3000/oauth/callback + +# Your sale contract address +VITE_SALE_CONTRACT_ADDRESS=0x439A7E681A71B1F3297e2c1b9c35bf226Ee24809 \ No newline at end of file