diff --git a/README.md b/README.md index ee195f9..59eafdd 100644 --- a/README.md +++ b/README.md @@ -102,3 +102,19 @@ cd P2Pix-Front-End # Run docker-compose up command docker-compose up ``` + +### Backend Communication + +Backend Repo: `https://gitea.kosmos.org/hueso/helpix` + +Backend Endpoint: `https://api.p2pix.co/release/1279331` + +curl -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer {api-key}" \ + -d '{"query": "{ depositAddeds { id seller token amount } }"}' \ +https://api.studio.thegraph.com/query/113713/p-2-pix/sepolia + +https://api.studio.thegraph.com/query/113713/p-2-pix/1 + +curl --request POST --url 'https://api.hm.bb.com.br/testes-portal-desenvolvedor/v1/boletos-pix/pagar?gw-app-key=95cad3f03fd9013a9d15005056825665' --header 'content-type: application/json' --data '{"pix":"00020101021226070503***63041654" }' \ No newline at end of file diff --git a/index.html b/index.html index a888544..233cc9c 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,11 @@ - + + + - Vite App + P2Pix
diff --git a/package.json b/package.json index d5f105e..be7f5d8 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,10 @@ "start": "vite --host=0.0.0.0 --port 3000", "build": "run-p type-check build-only", "preview": "vite preview", - "test": "vitest", "serve": "vue-cli-service serve", - "coverage": "vitest run --coverage", "build-only": "vite build", - "type-check": "vue-tsc --noEmit", - "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore", + "type-check": "vue-tsc --skipLibCheck --noEmit", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore --fix", "lint:fix": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" }, "dependencies": { @@ -18,12 +16,14 @@ "@headlessui/vue": "^1.7.3", "@heroicons/vue": "^2.0.12", "@vueuse/core": "^9.12.0", + "@web3-onboard/injected-wallets": "^2.11.2", + "@web3-onboard/vue": "^2.9.0", "alchemy-sdk": "^2.3.0", "axios": "^1.2.1", - "crc": "^3.8.0", "marked": "^4.2.12", - "pinia": "^2.0.23", "qrcode": "^1.5.1", + "viem": "^2.31.3", + "vite-svg-loader": "^5.1.0", "vue": "^3.2.41", "vue-markdown": "^2.2.4", "vue-router": "^4.1.5" @@ -31,33 +31,27 @@ "devDependencies": { "@babel/preset-env": "^7.20.2", "@babel/preset-typescript": "^7.18.6", - "@pinia/testing": "^0.0.14", "@rushstack/eslint-patch": "^1.1.4", "@types/crc": "^3.8.0", - "@types/jest": "^27.0.0", "@types/marked": "^4.0.8", "@types/node": "^16.11.68", "@types/qrcode": "^1.5.0", "@types/vue-markdown": "^2.2.1", "@vitejs/plugin-vue": "^3.1.2", "@vitejs/plugin-vue-jsx": "^2.0.1", - "@vitest/coverage-c8": "^0.28.2", "@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-typescript": "^11.0.0", - "@vue/test-utils": "^2.2.7", "@vue/tsconfig": "^0.1.3", + "@wagmi/cli": "^2.3.1", "autoprefixer": "^10.4.12", "eslint": "^8.22.0", "eslint-plugin-vue": "^9.3.0", - "ethers": "^5.7.2", - "jsdom": "^21.1.0", "npm-run-all": "^4.1.5", "postcss": "^8.4.18", "prettier": "^2.7.1", "tailwindcss": "^3.2.1", - "typescript": "~4.7.4", + "typescript": "~5.8.2", "vite": "^3.1.8", - "vitest": "^0.28.1", - "vue-tsc": "^1.0.8" + "vue-tsc": "^2.2.8" } } diff --git a/public/favicon.ico b/public/favicon.ico index df36fcf..7f1e4d0 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/p2pix.svg b/public/p2pix.svg new file mode 100644 index 0000000..de9cb96 --- /dev/null +++ b/public/p2pix.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + diff --git a/src/App.vue b/src/App.vue index 28dfc5b..b9816b9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,20 +1,66 @@ diff --git a/src/assets/Trial and expirations.jpg b/src/assets/Trial and expirations.jpg new file mode 100644 index 0000000..5e5f1a9 Binary files /dev/null and b/src/assets/Trial and expirations.jpg differ diff --git a/src/assets/bg.svg b/src/assets/bg.svg deleted file mode 100644 index 722c762..0000000 --- a/src/assets/bg.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/assets/brx.svg b/src/assets/brx.svg new file mode 100644 index 0000000..b599951 --- /dev/null +++ b/src/assets/brx.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/chevron.svg b/src/assets/chevron.svg new file mode 100644 index 0000000..d5b4633 --- /dev/null +++ b/src/assets/chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/chevronDown.svg b/src/assets/chevronDown.svg index 655a1c5..ede3e7e 100644 --- a/src/assets/chevronDown.svg +++ b/src/assets/chevronDown.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/chevronDownBlack.svg b/src/assets/chevronDownBlack.svg deleted file mode 100644 index 3fe97eb..0000000 --- a/src/assets/chevronDownBlack.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/chevronUp.svg b/src/assets/chevronUp.svg index 224851e..ba163e4 100644 --- a/src/assets/chevronUp.svg +++ b/src/assets/chevronUp.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/githubIcon.svg b/src/assets/githubIcon.svg index 8425052..29e8b17 100644 --- a/src/assets/githubIcon.svg +++ b/src/assets/githubIcon.svg @@ -1,3 +1,7 @@ - - + + + + + + diff --git a/src/assets/linkedinIcon.svg b/src/assets/linkedinIcon.svg new file mode 100644 index 0000000..f369e38 --- /dev/null +++ b/src/assets/linkedinIcon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/main.css b/src/assets/main.css index cdd3042..16eec84 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -6,11 +6,9 @@ #app { width: 100%; margin: 0 auto; - padding: 2rem; height: fit-content; min-height: 100vh; - background-image: url( './bg.svg' ); - background-size: cover; + background: radial-gradient(ellipse at 50% -50%, rgba(49, 46, 129, 1) 60%, rgba(24, 30, 42, 1) 80%); font-weight: normal; } @@ -26,3 +24,13 @@ a, background-color: hsla(160, 100%, 37%, 0.2); } } + +.main-container { + @apply flex w-full md:max-w-lg flex-col justify-center items-center px-4 sm:px-8 py-4 sm:py-6 gap-4 rounded-lg border border-gray-500 backdrop-blur-md drop-shadow-lg shadow-lg mt-10; +} + +input[type="number"] { + appearance: textfield; + -webkit-appearance: textfield; + -moz-appearance: textfield; +} \ No newline at end of file diff --git a/src/assets/rootstock.svg b/src/assets/rootstock.svg new file mode 100644 index 0000000..bee9d1f --- /dev/null +++ b/src/assets/rootstock.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/src/assets/sepolia.svg b/src/assets/sepolia.svg new file mode 100644 index 0000000..362923a --- /dev/null +++ b/src/assets/sepolia.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/transitions.css b/src/assets/transitions.css new file mode 100644 index 0000000..450238e --- /dev/null +++ b/src/assets/transitions.css @@ -0,0 +1,32 @@ +.dropdown-enter-active, +.dropdown-leave-active { + transition: all 0.3s ease; +} + +.dropdown-enter-from, +.dropdown-leave-to { + opacity: 0; + transform: translateY(-10px); +} + +.page-enter-active, +.page-leave-active { + transition: opacity 0.3s ease, transform 0.3s ease; +} + +.page-enter-from, +.page-leave-to { + opacity: 0; + transform: translateY(15px); +} + +.resize-enter-active, +.resize-leave-active { + max-height: 100px; + transition: all 0.3s ease; +} + +.resize-enter-from, +.resize-leave-to { + max-height: 0px; +} diff --git a/src/assets/twitterIcon.svg b/src/assets/twitterIcon.svg index 228b5a9..57ad34b 100644 --- a/src/assets/twitterIcon.svg +++ b/src/assets/twitterIcon.svg @@ -1,3 +1,7 @@ - - + + + + + + diff --git a/src/blockchain/__tests__/addresses.spec.ts b/src/blockchain/__tests__/addresses.spec.ts deleted file mode 100644 index ed768c0..0000000 --- a/src/blockchain/__tests__/addresses.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { expectTypeOf, it, expect } from "vitest"; -import { - getTokenAddress, - getP2PixAddress, - getProviderUrl, - isPossibleNetwork, - possibleChains, - network2Chain, -} from "../addresses"; - -import { setActivePinia, createPinia } from "pinia"; -import { NetworkEnum } from "@/model/NetworkEnum"; -import { useEtherStore } from "@/store/ether"; - -describe("addresses.ts types", () => { - it("My addresses.ts types work properly", () => { - expectTypeOf(getTokenAddress).toBeFunction(); - expectTypeOf(getP2PixAddress).toBeFunction(); - expectTypeOf(getProviderUrl).toBeFunction(); - expectTypeOf(isPossibleNetwork).toBeFunction(); - - expectTypeOf(possibleChains).toBeObject(); - expectTypeOf(network2Chain).toBeObject(); - }); -}); - -describe("addresses.ts functions", () => { - beforeEach(() => { - setActivePinia(createPinia()); - }); - - it("getTokenAddress Ethereum", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.ethereum); - expect(getTokenAddress()).toBe( - "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00" - ); - }); - - it("getTokenAddress Polygon", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.polygon); - expect(getTokenAddress()).toBe( - "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29" - ); - }); - - it("getTokenAddress Default", () => { - expect(getTokenAddress()).toBe( - "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00" - ); - }); - - it("getP2PixAddress Ethereum", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.ethereum); - expect(getP2PixAddress()).toBe( - "0x2414817FF64A114d91eCFA16a834d3fCf69103d4" - ); - }); - - it("getP2PixAddress Polygon", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.polygon); - expect(getP2PixAddress()).toBe( - "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00" - ); - }); - - it("getP2PixAddress Default", () => { - expect(getP2PixAddress()).toBe( - "0x2414817FF64A114d91eCFA16a834d3fCf69103d4" - ); - }); - - it("getProviderUrl Ethereum", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.ethereum); - expect(getProviderUrl()).toBe(import.meta.env.VITE_GOERLI_API_URL); - }); - - it("getProviderUrl Polygon", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.polygon); - expect(getProviderUrl()).toBe(import.meta.env.VITE_MUMBAI_API_URL); - }); - - it("getProviderUrl Default", () => { - expect(getProviderUrl()).toBe(import.meta.env.VITE_GOERLI_API_URL); - }); - - it("isPossibleNetwork Returns", () => { - const etherStore = useEtherStore(); - etherStore.setNetworkName(NetworkEnum.ethereum); - expect(isPossibleNetwork("0x5")).toBe(true); - expect(isPossibleNetwork("5")).toBe(true); - expect(isPossibleNetwork("0x13881")).toBe(true); - expect(isPossibleNetwork("80001")).toBe(true); - - expect(isPossibleNetwork("")).toBe(false); - expect(isPossibleNetwork(" ")).toBe(false); - expect(isPossibleNetwork("0x55")).toBe(false); - }); -}); diff --git a/src/blockchain/abi.ts b/src/blockchain/abi.ts new file mode 100644 index 0000000..d7af05e --- /dev/null +++ b/src/blockchain/abi.ts @@ -0,0 +1,2266 @@ +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// BaseUtils +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const baseUtilsAbi = [ + { type: 'error', inputs: [], name: 'AddressDenied' }, + { type: 'error', inputs: [], name: 'AlreadyReleased' }, + { type: 'error', inputs: [], name: 'AmountNotAllowed' }, + { type: 'error', inputs: [], name: 'DecOverflow' }, + { type: 'error', inputs: [], name: 'EmptyPixTarget' }, + { type: 'error', inputs: [], name: 'InvalidDeposit' }, + { type: 'error', inputs: [], name: 'InvalidSigner' }, + { type: 'error', inputs: [], name: 'LengthMismatch' }, + { type: 'error', inputs: [], name: 'LockExpired' }, + { type: 'error', inputs: [], name: 'LoopOverflow' }, + { type: 'error', inputs: [], name: 'MaxBalExceeded' }, + { type: 'error', inputs: [], name: 'NoTokens' }, + { type: 'error', inputs: [], name: 'NotEnoughTokens' }, + { type: 'error', inputs: [], name: 'NotExpired' }, + { type: 'error', inputs: [], name: 'NotInitialized' }, + { type: 'error', inputs: [], name: 'OnlySeller' }, + { type: 'error', inputs: [], name: 'Reentrancy' }, + { type: 'error', inputs: [], name: 'StaticCallFailed' }, + { type: 'error', inputs: [], name: 'TokenDenied' }, + { type: 'error', inputs: [], name: 'TxAlreadyUsed' }, + { type: 'error', inputs: [], name: 'Unauthorized' }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'token', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'AllowedERC20Updated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'owner', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'FundsWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockID', + internalType: 'uint256', + type: 'uint256', + indexed: true, + }, + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'blocks', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockBlocksUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReleased', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReturned', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'user', internalType: 'address', type: 'address', indexed: true }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnerUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'reputation', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'ReputationUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'merkleRoot', + internalType: 'bytes32', + type: 'bytes32', + indexed: true, + }, + ], + name: 'RootUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'forwarder', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'TrustedForwarderUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: false }, + ], + name: 'ValidSet', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'signers', + internalType: 'address[]', + type: 'address[]', + indexed: false, + }, + ], + name: 'ValidSignersUpdated', + }, + { + type: 'function', + inputs: [{ name: '_addr', internalType: 'address', type: 'address' }], + name: '_castAddrToKey', + outputs: [{ name: '_key', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [{ name: '_key', internalType: 'uint256', type: 'uint256' }], + name: '_castKeyToAddr', + outputs: [{ name: '_addr', internalType: 'address', type: 'address' }], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [ + { name: 'erc20', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'allowedERC20s', + outputs: [{ name: 'state', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'defaultLockBlocks', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'str', internalType: 'string', type: 'string' }], + name: 'getStr', + outputs: [{ name: 'strEnc', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [{ name: 'forwarder', internalType: 'address', type: 'address' }], + name: 'isTrustedForwarder', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'owner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'reputation', + outputs: [ + { name: '', internalType: 'contract IReputation', type: 'address' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'sellerKey', internalType: 'address', type: 'address' }], + name: 'sellerAllowList', + outputs: [{ name: 'root', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '_blocks', internalType: 'uint256', type: 'uint256' }], + name: 'setDefaultLockBlocks', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: 'newOwner', internalType: 'address', type: 'address' }], + name: 'setOwner', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { + name: '_reputation', + internalType: 'contract IReputation', + type: 'address', + }, + ], + name: 'setReputation', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'forwarders', internalType: 'address[]', type: 'address[]' }, + { name: 'states', internalType: 'bool[]', type: 'bool[]' }, + ], + name: 'setTrustedFowarders', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_validSigners', internalType: 'address[]', type: 'address[]' }, + ], + name: 'setValidSigners', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_tokens', internalType: 'contract ERC20[]', type: 'address[]' }, + { name: '_states', internalType: 'bool[]', type: 'bool[]' }, + ], + name: 'tokenSettings', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'trustedForwarders', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'message', internalType: 'bytes32', type: 'bytes32' }], + name: 'usedTransactions', + outputs: [{ name: 'used', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'signer', internalType: 'uint256', type: 'uint256' }], + name: 'validBacenSigners', + outputs: [{ name: 'valid', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'withdrawBalance', + outputs: [], + stateMutability: 'nonpayable', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ECDSA +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const ecdsaAbi = [ + { type: 'error', inputs: [], name: 'InvalidSignature' }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ERC20 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const erc20Abi = [ + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'owner', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'spender', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'Approval', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'from', internalType: 'address', type: 'address', indexed: true }, + { name: 'to', internalType: 'address', type: 'address', indexed: true }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'Transfer', + }, + { + type: 'function', + inputs: [], + name: 'DOMAIN_SEPARATOR', + outputs: [{ name: '', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: '', internalType: 'address', type: 'address' }, + { name: '', internalType: 'address', type: 'address' }, + ], + name: 'allowance', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'spender', internalType: 'address', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'balanceOf', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'decimals', + outputs: [{ name: '', internalType: 'uint8', type: 'uint8' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'name', + outputs: [{ name: '', internalType: 'string', type: 'string' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'nonces', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'owner', internalType: 'address', type: 'address' }, + { name: 'spender', internalType: 'address', type: 'address' }, + { name: 'value', internalType: 'uint256', type: 'uint256' }, + { name: 'deadline', internalType: 'uint256', type: 'uint256' }, + { name: 'v', internalType: 'uint8', type: 'uint8' }, + { name: 'r', internalType: 'bytes32', type: 'bytes32' }, + { name: 's', internalType: 'bytes32', type: 'bytes32' }, + ], + name: 'permit', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'symbol', + outputs: [{ name: '', internalType: 'string', type: 'string' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'totalSupply', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'to', internalType: 'address', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + ], + name: 'transfer', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'from', internalType: 'address', type: 'address' }, + { name: 'to', internalType: 'address', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + ], + name: 'transferFrom', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'nonpayable', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ERC2771Context +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const erc2771ContextAbi = [ + { + type: 'function', + inputs: [{ name: 'forwarder', internalType: 'address', type: 'address' }], + name: 'isTrustedForwarder', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'trustedForwarders', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// EventAndErrors +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const eventAndErrorsAbi = [ + { type: 'error', inputs: [], name: 'AddressDenied' }, + { type: 'error', inputs: [], name: 'AlreadyReleased' }, + { type: 'error', inputs: [], name: 'AmountNotAllowed' }, + { type: 'error', inputs: [], name: 'DecOverflow' }, + { type: 'error', inputs: [], name: 'EmptyPixTarget' }, + { type: 'error', inputs: [], name: 'InvalidDeposit' }, + { type: 'error', inputs: [], name: 'InvalidSigner' }, + { type: 'error', inputs: [], name: 'LengthMismatch' }, + { type: 'error', inputs: [], name: 'LockExpired' }, + { type: 'error', inputs: [], name: 'LoopOverflow' }, + { type: 'error', inputs: [], name: 'MaxBalExceeded' }, + { type: 'error', inputs: [], name: 'NoTokens' }, + { type: 'error', inputs: [], name: 'NotEnoughTokens' }, + { type: 'error', inputs: [], name: 'NotExpired' }, + { type: 'error', inputs: [], name: 'NotInitialized' }, + { type: 'error', inputs: [], name: 'OnlySeller' }, + { type: 'error', inputs: [], name: 'StaticCallFailed' }, + { type: 'error', inputs: [], name: 'TokenDenied' }, + { type: 'error', inputs: [], name: 'TxAlreadyUsed' }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'token', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'AllowedERC20Updated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'owner', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'FundsWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockID', + internalType: 'uint256', + type: 'uint256', + indexed: true, + }, + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'blocks', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockBlocksUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReleased', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReturned', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'reputation', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'ReputationUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'merkleRoot', + internalType: 'bytes32', + type: 'bytes32', + indexed: true, + }, + ], + name: 'RootUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'forwarder', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'TrustedForwarderUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: false }, + ], + name: 'ValidSet', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'signers', + internalType: 'address[]', + type: 'address[]', + indexed: false, + }, + ], + name: 'ValidSignersUpdated', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IReputation +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const iReputationAbi = [ + { + type: 'function', + inputs: [{ name: '_userCredit', internalType: 'uint256', type: 'uint256' }], + name: 'limiter', + outputs: [ + { name: '_spendLimit', internalType: 'uint256', type: 'uint256' }, + ], + stateMutability: 'pure', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MockToken +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const mockTokenAbi = [ + { + type: 'constructor', + inputs: [{ name: 'supply', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'nonpayable', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'owner', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'spender', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'Approval', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'from', internalType: 'address', type: 'address', indexed: true }, + { name: 'to', internalType: 'address', type: 'address', indexed: true }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'Transfer', + }, + { + type: 'function', + inputs: [], + name: 'DOMAIN_SEPARATOR', + outputs: [{ name: '', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: '', internalType: 'address', type: 'address' }, + { name: '', internalType: 'address', type: 'address' }, + ], + name: 'allowance', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'spender', internalType: 'address', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'balanceOf', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'decimals', + outputs: [{ name: '', internalType: 'uint8', type: 'uint8' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'to', internalType: 'address[]', type: 'address[]' }, + { name: 'value', internalType: 'uint256', type: 'uint256' }, + ], + name: 'mint', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'name', + outputs: [{ name: '', internalType: 'string', type: 'string' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'nonces', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'owner', internalType: 'address', type: 'address' }, + { name: 'spender', internalType: 'address', type: 'address' }, + { name: 'value', internalType: 'uint256', type: 'uint256' }, + { name: 'deadline', internalType: 'uint256', type: 'uint256' }, + { name: 'v', internalType: 'uint8', type: 'uint8' }, + { name: 'r', internalType: 'bytes32', type: 'bytes32' }, + { name: 's', internalType: 'bytes32', type: 'bytes32' }, + ], + name: 'permit', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'symbol', + outputs: [{ name: '', internalType: 'string', type: 'string' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'totalSupply', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'to', internalType: 'address', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + ], + name: 'transfer', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'from', internalType: 'address', type: 'address' }, + { name: 'to', internalType: 'address', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + ], + name: 'transferFrom', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'nonpayable', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Multicall +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const multicallAbi = [ + { type: 'constructor', inputs: [], stateMutability: 'payable' }, + { + type: 'error', + inputs: [{ name: 'reason', internalType: 'string', type: 'string' }], + name: 'CallFailed', + }, + { + type: 'function', + inputs: [ + { + name: 'calls', + internalType: 'struct Multicall.Call[]', + type: 'tuple[]', + components: [ + { name: 'target', internalType: 'address', type: 'address' }, + { name: 'callData', internalType: 'bytes', type: 'bytes' }, + ], + }, + ], + name: 'mtc1', + outputs: [ + { name: '', internalType: 'uint256', type: 'uint256' }, + { name: '', internalType: 'bytes[]', type: 'bytes[]' }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { + name: 'calls', + internalType: 'struct Multicall.Call[]', + type: 'tuple[]', + components: [ + { name: 'target', internalType: 'address', type: 'address' }, + { name: 'callData', internalType: 'bytes', type: 'bytes' }, + ], + }, + ], + name: 'mtc2', + outputs: [ + { name: '', internalType: 'uint256', type: 'uint256' }, + { name: '', internalType: 'bytes32', type: 'bytes32' }, + { + name: '', + internalType: 'struct Multicall.Result[]', + type: 'tuple[]', + components: [ + { name: 'success', internalType: 'bool', type: 'bool' }, + { name: 'returnData', internalType: 'bytes', type: 'bytes' }, + ], + }, + ], + stateMutability: 'nonpayable', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Owned +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const ownedAbi = [ + { type: 'error', inputs: [], name: 'Unauthorized' }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'user', internalType: 'address', type: 'address', indexed: true }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnerUpdated', + }, + { + type: 'function', + inputs: [], + name: 'owner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'newOwner', internalType: 'address', type: 'address' }], + name: 'setOwner', + outputs: [], + stateMutability: 'nonpayable', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// OwnerSettings +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const ownerSettingsAbi = [ + { type: 'error', inputs: [], name: 'AddressDenied' }, + { type: 'error', inputs: [], name: 'AlreadyReleased' }, + { type: 'error', inputs: [], name: 'AmountNotAllowed' }, + { type: 'error', inputs: [], name: 'DecOverflow' }, + { type: 'error', inputs: [], name: 'EmptyPixTarget' }, + { type: 'error', inputs: [], name: 'InvalidDeposit' }, + { type: 'error', inputs: [], name: 'InvalidSigner' }, + { type: 'error', inputs: [], name: 'LengthMismatch' }, + { type: 'error', inputs: [], name: 'LockExpired' }, + { type: 'error', inputs: [], name: 'LoopOverflow' }, + { type: 'error', inputs: [], name: 'MaxBalExceeded' }, + { type: 'error', inputs: [], name: 'NoTokens' }, + { type: 'error', inputs: [], name: 'NotEnoughTokens' }, + { type: 'error', inputs: [], name: 'NotExpired' }, + { type: 'error', inputs: [], name: 'NotInitialized' }, + { type: 'error', inputs: [], name: 'OnlySeller' }, + { type: 'error', inputs: [], name: 'StaticCallFailed' }, + { type: 'error', inputs: [], name: 'TokenDenied' }, + { type: 'error', inputs: [], name: 'TxAlreadyUsed' }, + { type: 'error', inputs: [], name: 'Unauthorized' }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'token', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'AllowedERC20Updated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'owner', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'FundsWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockID', + internalType: 'uint256', + type: 'uint256', + indexed: true, + }, + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'blocks', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockBlocksUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReleased', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReturned', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'user', internalType: 'address', type: 'address', indexed: true }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnerUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'reputation', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'ReputationUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'merkleRoot', + internalType: 'bytes32', + type: 'bytes32', + indexed: true, + }, + ], + name: 'RootUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'forwarder', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'TrustedForwarderUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: false }, + ], + name: 'ValidSet', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'signers', + internalType: 'address[]', + type: 'address[]', + indexed: false, + }, + ], + name: 'ValidSignersUpdated', + }, + { + type: 'function', + inputs: [ + { name: 'erc20', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'allowedERC20s', + outputs: [{ name: 'state', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'defaultLockBlocks', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'forwarder', internalType: 'address', type: 'address' }], + name: 'isTrustedForwarder', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'owner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'reputation', + outputs: [ + { name: '', internalType: 'contract IReputation', type: 'address' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'sellerKey', internalType: 'address', type: 'address' }], + name: 'sellerAllowList', + outputs: [{ name: 'root', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '_blocks', internalType: 'uint256', type: 'uint256' }], + name: 'setDefaultLockBlocks', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: 'newOwner', internalType: 'address', type: 'address' }], + name: 'setOwner', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { + name: '_reputation', + internalType: 'contract IReputation', + type: 'address', + }, + ], + name: 'setReputation', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'forwarders', internalType: 'address[]', type: 'address[]' }, + { name: 'states', internalType: 'bool[]', type: 'bool[]' }, + ], + name: 'setTrustedFowarders', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_validSigners', internalType: 'address[]', type: 'address[]' }, + ], + name: 'setValidSigners', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_tokens', internalType: 'contract ERC20[]', type: 'address[]' }, + { name: '_states', internalType: 'bool[]', type: 'bool[]' }, + ], + name: 'tokenSettings', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'trustedForwarders', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'signer', internalType: 'uint256', type: 'uint256' }], + name: 'validBacenSigners', + outputs: [{ name: 'valid', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'withdrawBalance', + outputs: [], + stateMutability: 'nonpayable', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// P2PIX +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const p2PixAbi = [ + { + type: 'constructor', + inputs: [ + { name: 'defaultBlocks', internalType: 'uint256', type: 'uint256' }, + { name: 'validSigners', internalType: 'address[]', type: 'address[]' }, + { name: '_reputation', internalType: 'address', type: 'address' }, + { name: 'tokens', internalType: 'contract ERC20[]', type: 'address[]' }, + { name: 'tokenStates', internalType: 'bool[]', type: 'bool[]' }, + ], + stateMutability: 'payable', + }, + { type: 'error', inputs: [], name: 'AddressDenied' }, + { type: 'error', inputs: [], name: 'AlreadyReleased' }, + { type: 'error', inputs: [], name: 'AmountNotAllowed' }, + { type: 'error', inputs: [], name: 'DecOverflow' }, + { type: 'error', inputs: [], name: 'EmptyPixTarget' }, + { type: 'error', inputs: [], name: 'InvalidDeposit' }, + { type: 'error', inputs: [], name: 'InvalidSigner' }, + { type: 'error', inputs: [], name: 'LengthMismatch' }, + { type: 'error', inputs: [], name: 'LockExpired' }, + { type: 'error', inputs: [], name: 'LoopOverflow' }, + { type: 'error', inputs: [], name: 'MaxBalExceeded' }, + { type: 'error', inputs: [], name: 'NoTokens' }, + { type: 'error', inputs: [], name: 'NotEnoughTokens' }, + { type: 'error', inputs: [], name: 'NotExpired' }, + { type: 'error', inputs: [], name: 'NotInitialized' }, + { type: 'error', inputs: [], name: 'OnlySeller' }, + { type: 'error', inputs: [], name: 'Reentrancy' }, + { type: 'error', inputs: [], name: 'StaticCallFailed' }, + { type: 'error', inputs: [], name: 'TokenDenied' }, + { type: 'error', inputs: [], name: 'TxAlreadyUsed' }, + { type: 'error', inputs: [], name: 'Unauthorized' }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'token', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'AllowedERC20Updated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'DepositWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'owner', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'FundsWithdrawn', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockID', + internalType: 'uint256', + type: 'uint256', + indexed: true, + }, + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockAdded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'blocks', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockBlocksUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReleased', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'buyer', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'lockId', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'LockReturned', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'user', internalType: 'address', type: 'address', indexed: true }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnerUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'reputation', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'ReputationUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'merkleRoot', + internalType: 'bytes32', + type: 'bytes32', + indexed: true, + }, + ], + name: 'RootUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'forwarder', + internalType: 'address', + type: 'address', + indexed: true, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: true }, + ], + name: 'TrustedForwarderUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'seller', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'token', + internalType: 'contract ERC20', + type: 'address', + indexed: false, + }, + { name: 'state', internalType: 'bool', type: 'bool', indexed: false }, + ], + name: 'ValidSet', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'signers', + internalType: 'address[]', + type: 'address[]', + indexed: false, + }, + ], + name: 'ValidSignersUpdated', + }, + { + type: 'function', + inputs: [{ name: '_addr', internalType: 'address', type: 'address' }], + name: '_castAddrToKey', + outputs: [{ name: '_key', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [{ name: '_key', internalType: 'uint256', type: 'uint256' }], + name: '_castKeyToAddr', + outputs: [{ name: '_addr', internalType: 'address', type: 'address' }], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [ + { name: 'erc20', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'allowedERC20s', + outputs: [{ name: 'state', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'defaultLockBlocks', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'pixTarget', internalType: 'string', type: 'string' }, + { name: 'allowlistRoot', internalType: 'bytes32', type: 'bytes32' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + { name: 'amount', internalType: 'uint96', type: 'uint96' }, + { name: 'valid', internalType: 'bool', type: 'bool' }, + ], + name: 'deposit', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'seller', internalType: 'address', type: 'address' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'getBalance', + outputs: [{ name: 'bal', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'sellers', internalType: 'address[]', type: 'address[]' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'getBalances', + outputs: [{ name: '', internalType: 'uint256[]', type: 'uint256[]' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'ids', internalType: 'uint256[]', type: 'uint256[]' }], + name: 'getLocksStatus', + outputs: [ + { name: '', internalType: 'uint256[]', type: 'uint256[]' }, + { + name: '', + internalType: 'enum DataTypes.LockStatus[]', + type: 'uint8[]', + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'seller', internalType: 'address', type: 'address' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'getPixTarget', + outputs: [{ name: 'pixTarget', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'seller', internalType: 'address', type: 'address' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'getPixTargetString', + outputs: [{ name: 'pixTarget', internalType: 'string', type: 'string' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'str', internalType: 'string', type: 'string' }], + name: 'getStr', + outputs: [{ name: 'strEnc', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [ + { name: 'seller', internalType: 'address', type: 'address' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + ], + name: 'getValid', + outputs: [{ name: 'valid', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'forwarder', internalType: 'address', type: 'address' }], + name: 'isTrustedForwarder', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'seller', internalType: 'address', type: 'address' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + { name: 'amount', internalType: 'uint80', type: 'uint80' }, + { name: 'merkleProof', internalType: 'bytes32[]', type: 'bytes32[]' }, + { name: 'expiredLocks', internalType: 'uint256[]', type: 'uint256[]' }, + ], + name: 'lock', + outputs: [{ name: 'lockID', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'lockCounter', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + name: 'mapLocks', + outputs: [ + { name: 'counter', internalType: 'uint256', type: 'uint256' }, + { name: 'expirationBlock', internalType: 'uint256', type: 'uint256' }, + { name: 'pixTarget', internalType: 'bytes32', type: 'bytes32' }, + { name: 'amount', internalType: 'uint80', type: 'uint80' }, + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + { name: 'buyerAddress', internalType: 'address', type: 'address' }, + { name: 'seller', internalType: 'address', type: 'address' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'owner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'lockID', internalType: 'uint256', type: 'uint256' }, + { name: 'pixTimestamp', internalType: 'bytes32', type: 'bytes32' }, + { name: 'signature', internalType: 'bytes', type: 'bytes' }, + ], + name: 'release', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'reputation', + outputs: [ + { name: '', internalType: 'contract IReputation', type: 'address' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'sellerKey', internalType: 'address', type: 'address' }], + name: 'sellerAllowList', + outputs: [{ name: 'root', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '_blocks', internalType: 'uint256', type: 'uint256' }], + name: 'setDefaultLockBlocks', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: 'newOwner', internalType: 'address', type: 'address' }], + name: 'setOwner', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { + name: '_reputation', + internalType: 'contract IReputation', + type: 'address', + }, + ], + name: 'setReputation', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'addr', internalType: 'address', type: 'address' }, + { name: 'merkleroot', internalType: 'bytes32', type: 'bytes32' }, + ], + name: 'setRoot', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'forwarders', internalType: 'address[]', type: 'address[]' }, + { name: 'states', internalType: 'bool[]', type: 'bool[]' }, + ], + name: 'setTrustedFowarders', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_validSigners', internalType: 'address[]', type: 'address[]' }, + ], + name: 'setValidSigners', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + { name: 'state', internalType: 'bool', type: 'bool' }, + ], + name: 'setValidState', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_tokens', internalType: 'contract ERC20[]', type: 'address[]' }, + { name: '_states', internalType: 'bool[]', type: 'bool[]' }, + ], + name: 'tokenSettings', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'trustedForwarders', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'lockIDs', internalType: 'uint256[]', type: 'uint256[]' }], + name: 'unlockExpired', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: 'message', internalType: 'bytes32', type: 'bytes32' }], + name: 'usedTransactions', + outputs: [{ name: 'used', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + name: 'userRecord', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'signer', internalType: 'uint256', type: 'uint256' }], + name: 'validBacenSigners', + outputs: [{ name: 'valid', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'token', internalType: 'contract ERC20', type: 'address' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + { name: 'expiredLocks', internalType: 'uint256[]', type: 'uint256[]' }, + ], + name: 'withdraw', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'withdrawBalance', + outputs: [], + stateMutability: 'nonpayable', + }, + { type: 'receive', stateMutability: 'payable' }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ReentrancyGuard +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const reentrancyGuardAbi = [ + { type: 'error', inputs: [], name: 'Reentrancy' }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Reputation +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const reputationAbi = [ + { type: 'constructor', inputs: [], stateMutability: 'payable' }, + { + type: 'function', + inputs: [{ name: '_userCredit', internalType: 'uint256', type: 'uint256' }], + name: 'limiter', + outputs: [ + { name: '_spendLimit', internalType: 'uint256', type: 'uint256' }, + ], + stateMutability: 'pure', + }, + { + type: 'function', + inputs: [], + name: 'magicValue', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'maxLimit', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SafeTransferLib +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const safeTransferLibAbi = [ + { type: 'error', inputs: [], name: 'ETHTransferFailed' }, + { type: 'error', inputs: [], name: 'TransferFailed' }, + { type: 'error', inputs: [], name: 'TransferFromFailed' }, +] as const diff --git a/src/blockchain/addresses.ts b/src/blockchain/addresses.ts index ef486b5..dcd1833 100644 --- a/src/blockchain/addresses.ts +++ b/src/blockchain/addresses.ts @@ -1,64 +1,70 @@ -import { useEtherStore } from "@/store/ether"; -import { NetworkEnum } from "@/model/NetworkEnum"; +import { useUser } from "@/composables/useUser"; +import { NetworkEnum, TokenEnum } from "@/model/NetworkEnum"; +import { createPublicClient, http, type Address } from "viem"; +import { sepolia, rootstock } from "viem/chains"; -const getTokenAddress = (network?: NetworkEnum): string => { - const etherStore = useEtherStore(); - - const possibleTokenAddresses: { [key: string]: string } = { - Ethereum: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00", - Polygon: "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29", - }; - - return possibleTokenAddresses[network ? network : etherStore.networkName]; +const Tokens: { [key in NetworkEnum]: { [key in TokenEnum]: Address } } = { + [NetworkEnum.sepolia]: { + BRZ: "0x3eBE67A2C7bdB2081CBd34ba3281E90377462289", + // BRX: "0x3eBE67A2C7bdB2081CBd34ba3281E90377462289", + }, + [NetworkEnum.rootstock]: { + BRZ: "0xfE841c74250e57640390f46d914C88d22C51e82e", + // BRX: "0xfE841c74250e57640390f46d914C88d22C51e82e", + }, }; -const getP2PixAddress = (network?: NetworkEnum): string => { - const etherStore = useEtherStore(); - - const possibleP2PixAddresses: { [key: string]: string } = { - Ethereum: "0x2414817FF64A114d91eCFA16a834d3fCf69103d4", - Polygon: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00", - }; - - return possibleP2PixAddresses[network ? network : etherStore.networkName]; -}; - -const getProviderUrl = (): string => { - const etherStore = useEtherStore(); - - const possibleProvidersUrls: { [key: string]: string } = { - Ethereum: import.meta.env.VITE_GOERLI_API_URL, - Polygon: import.meta.env.VITE_MUMBAI_API_URL, - }; - - return possibleProvidersUrls[etherStore.networkName]; -}; - -const possibleChains: { [key: string]: NetworkEnum } = { - "0x5": NetworkEnum.ethereum, - "5": NetworkEnum.ethereum, - "0x13881": NetworkEnum.polygon, - "80001": NetworkEnum.polygon, -}; - -const network2Chain: { [key: string]: string } = { - Ethereum: "0x5", - Polygon: "0x13881", - Localhost: "0x7a69", -}; - -const isPossibleNetwork = (networkChain: string): boolean => { - if (Object.keys(possibleChains).includes(networkChain)) { - return true; +export const getTokenByAddress = (address: Address) => { + const user = useUser(); + const networksTokens = Tokens[user.networkName.value]; + for (const [token, tokenAddress] of Object.entries(networksTokens)) { + if (tokenAddress.toLowerCase() === address.toLowerCase()) { + return token; + } } - return false; + return null; }; -export { - getTokenAddress, - getProviderUrl, - possibleChains, - network2Chain, - isPossibleNetwork, - getP2PixAddress, +export const getTokenAddress = ( + token: TokenEnum, + network?: NetworkEnum +): Address => { + const user = useUser(); + return Tokens[network ? network : user.networkName.value][ + token + ]; +}; + +export const getP2PixAddress = (network?: NetworkEnum): Address => { + const user = useUser(); + const possibleP2PixAddresses: { [key in NetworkEnum]: Address } = { + [NetworkEnum.sepolia]: "0xb7cD135F5eFD9760981e02E2a898790b688939fe", + [NetworkEnum.rootstock]: "0x98ba35eb14b38D6Aa709338283af3e922476dE34", + }; + + return possibleP2PixAddresses[ + network ? network : user.networkName.value + ]; +}; + +export const getProviderUrl = (network?: NetworkEnum): string => { + const user = useUser(); + const possibleProvidersUrls: { [key in NetworkEnum]: string } = { + [NetworkEnum.sepolia]: import.meta.env.VITE_SEPOLIA_API_URL, + [NetworkEnum.rootstock]: import.meta.env.VITE_RSK_API_URL, + }; + + return possibleProvidersUrls[network || user.networkName.value]; +}; + +export const getProviderByNetwork = (network: NetworkEnum) => { + const chain = network === NetworkEnum.sepolia ? sepolia : rootstock; + return createPublicClient({ + chain, + transport: http(getProviderUrl(network)), + }); +}; + +export const isPossibleNetwork = (networkChain: NetworkEnum): boolean => { + return Number(networkChain) in NetworkEnum; }; diff --git a/src/blockchain/buyerMethods.ts b/src/blockchain/buyerMethods.ts index d44b38b..ec54e15 100644 --- a/src/blockchain/buyerMethods.ts +++ b/src/blockchain/buyerMethods.ts @@ -1,100 +1,95 @@ -import { useEtherStore } from "@/store/ether"; +import { getContract } from "./provider"; +import { getTokenAddress } from "./addresses"; +import { + bytesToHex, + encodeAbiParameters, + keccak256, + parseAbiParameters, + parseEther, + stringToBytes, + stringToHex, + toBytes, + type Address, +} from "viem"; +import type { TokenEnum } from "@/model/NetworkEnum"; -import { getContract, getProvider } from "./provider"; -import { getP2PixAddress, getTokenAddress } from "./addresses"; - -import p2pix from "@/utils/smart_contract_files/P2PIX.json"; - -import { BigNumber, ethers } from "ethers"; -import { parseEther } from "ethers/lib/utils"; - -const addLock = async ( - seller: string, - token: string, +export const addLock = async ( + sellerAddress: Address, + tokenAddress: Address, amount: number -): Promise => { - const etherStore = useEtherStore(); +): Promise => { + const { address, abi, wallet, client, account } = await getContract(); + const parsedAmount = parseEther(amount.toString()); - const p2pContract = getContract(); + if (!wallet) { + throw new Error("Wallet not connected"); + } - const lock = await p2pContract.lock( - seller, - token, - etherStore.walletAddress, // String "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (Example) - ethers.constants.AddressZero, // String "0x0000000000000000000000000000000000000000" - 0, - parseEther(String(amount)), // BigNumber - [], - [] - ); + const { result, request } = await client.simulateContract({ + address, + abi, + functionName: "lock", + args: [sellerAddress, tokenAddress, parsedAmount, [], []], + account, + }); + const hash = await wallet.writeContract(request); + const receipt = await client.waitForTransactionReceipt({ hash }); - const lock_rec = await lock.wait(); - const [t] = lock_rec.events; + if (!receipt.status) + throw new Error("Transaction failed: " + receipt.transactionHash); - return String(t.args.lockID); + return result; }; -const releaseLock = async ( - pixKey: number, - amount: number, - e2eId: string, - lockId: string +export const withdrawDeposit = async ( + amount: string, + token: TokenEnum +): Promise => { + const { address, abi, wallet, client, account } = await getContract(); + + if (!wallet) { + throw new Error("Wallet not connected"); + } + + const tokenAddress = getTokenAddress(token); + + const { request } = await client.simulateContract({ + address, + abi, + functionName: "withdraw", + args: [tokenAddress, parseEther(amount), []], + account + }); + + const hash = await wallet.writeContract(request); + const receipt = await client.waitForTransactionReceipt({ hash }); + + return receipt.status === "success"; +}; + +export const releaseLock = async ( + lockID: bigint, + pixtarget: string, + signature: string ): Promise => { - const mockBacenSigner = new ethers.Wallet( - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ); + const { address, abi, wallet, client, account } = await getContract(); - const messageToSign = ethers.utils.solidityKeccak256( - ["uint160", "uint256", "bytes32"], - [ - pixKey, - parseEther(String(amount)), - ethers.utils.formatBytes32String(e2eId), - ] - ); + console.log("Releasing lock", { lockID, pixtarget, signature }); + if (!wallet) { + throw new Error("Wallet not connected"); + } - const messageHashBytes = ethers.utils.arrayify(messageToSign); - const flatSig = await mockBacenSigner.signMessage(messageHashBytes); - const provider = getProvider(); + // Convert pixtarget to bytes32 + const pixTimestamp = keccak256(stringToHex(pixtarget, { size: 32 }) ); - const sig = ethers.utils.splitSignature(flatSig); + const { request } = await client.simulateContract({ + address, + abi, + functionName: "release", + args: [BigInt(lockID), pixTimestamp, stringToHex(signature)], + account + }); - const signer = provider.getSigner(); - const p2pContract = new ethers.Contract(getP2PixAddress(), p2pix.abi, signer); - - const release = await p2pContract.release( - BigNumber.from(lockId), - ethers.constants.AddressZero, - ethers.utils.formatBytes32String(e2eId), - sig.r, - sig.s, - sig.v - ); - await release.wait(); - - return release; + const hash = await wallet.writeContract(request); + return client.waitForTransactionReceipt({ hash }); }; - -const cancelDeposit = async (depositId: BigNumber): Promise => { - const contract = getContract(); - - const cancel = await contract.cancelDeposit(depositId); - await cancel.wait(); - - return cancel; -}; - -const withdrawDeposit = async (amount: string): Promise => { - const contract = getContract(); - - const withdraw = await contract.withdraw( - getTokenAddress(), - parseEther(String(amount)), - [] - ); - await withdraw.wait(); - - return withdraw; -}; - -export { cancelDeposit, withdrawDeposit, addLock, releaseLock }; diff --git a/src/blockchain/events.ts b/src/blockchain/events.ts index 18ae3be..6c460a6 100644 --- a/src/blockchain/events.ts +++ b/src/blockchain/events.ts @@ -1,126 +1,176 @@ -import { useEtherStore } from "@/store/ether"; -import { Contract, ethers } from "ethers"; +import { useUser } from "@/composables/useUser"; +import { formatEther, toHex, stringToHex } from "viem"; +import type { PublicClient, Address } from "viem"; -import p2pix from "@/utils/smart_contract_files/P2PIX.json"; -import { formatEther } from "ethers/lib/utils"; import { getContract } from "./provider"; -import type { ValidDeposit } from "@/model/ValidDeposit"; import { getP2PixAddress, getTokenAddress } from "./addresses"; -import { NetworkEnum } from "@/model/NetworkEnum"; +import { p2PixAbi } from "./abi" +import type { ValidDeposit } from "@/model/ValidDeposit"; +import { getNetworkSubgraphURL, NetworkEnum, TokenEnum } from "@/model/NetworkEnum"; import type { UnreleasedLock } from "@/model/UnreleasedLock"; -import type { Pix } from "@/model/Pix"; +import type { LockStatus } from "@/model/LockStatus" const getNetworksLiquidity = async (): Promise => { - const etherStore = useEtherStore(); + const user = useUser(); + user.setLoadingNetworkLiquidity(true); - const goerliProvider = new ethers.providers.JsonRpcProvider( - import.meta.env.VITE_GOERLI_API_URL, - 5 - ); // goerli provider - const mumbaiProvider = new ethers.providers.JsonRpcProvider( - import.meta.env.VITE_MUMBAI_API_URL, - 80001 - ); // mumbai provider + const depositLists: ValidDeposit[][] = []; - const p2pContractGoerli = new ethers.Contract( - getP2PixAddress(NetworkEnum.ethereum), - p2pix.abi, - goerliProvider + for (const network of Object.values(NetworkEnum).filter( + (v) => !isNaN(Number(v)) + )) { + const deposits = await getValidDeposits( + getTokenAddress(user.selectedToken.value), + Number(network) + ); + if (deposits) depositLists.push(deposits); + } + + const allDeposits = depositLists.flat(); + user.setDepositsValidList(allDeposits); + user.setLoadingNetworkLiquidity(false); +}; + +const getParticipantID = async ( + seller: string, + token: string +): Promise => { + const { address, abi, client } = await getContract(); + + const participantIDHex = await client.readContract({ + address, + abi, + functionName: "getPixTarget", + args: [seller, token], + }); + + // Remove '0x' prefix and convert hex to UTF-8 string + const hexString = + typeof participantIDHex === "string" + ? participantIDHex + : toHex(participantIDHex as bigint); + if (!hexString) throw new Error("Participant ID not found"); + const bytes = new Uint8Array( + hexString + .slice(2) + .match(/.{1,2}/g)! + .map((byte: string) => parseInt(byte, 16)) ); - const p2pContractMumbai = new ethers.Contract( - getP2PixAddress(NetworkEnum.polygon), - p2pix.abi, - mumbaiProvider - ); - - etherStore.setLoadingNetworkLiquidity(true); - const depositListGoerli = await getValidDeposits( - getTokenAddress(NetworkEnum.ethereum), - p2pContractGoerli - ); - - const depositListMumbai = await getValidDeposits( - getTokenAddress(NetworkEnum.polygon), - p2pContractMumbai - ); - - etherStore.setDepositsValidListGoerli(depositListGoerli); - etherStore.setDepositsValidListMumbai(depositListMumbai); - etherStore.setLoadingNetworkLiquidity(false); + // Remove null bytes from the end of the string + return new TextDecoder().decode(bytes).replace(/\0/g, ""); }; const getValidDeposits = async ( - token: string, - contract?: Contract + token: Address, + network: NetworkEnum, + contractInfo?: { client: PublicClient; address: Address } ): Promise => { - let p2pContract: Contract; + let client: PublicClient, abi; - if (contract) { - p2pContract = contract; + if (contractInfo) { + ({ client } = contractInfo); + abi = p2PixAbi; } else { - p2pContract = getContract(true); + ({ abi, client } = await getContract(true)); } - const filterDeposits = p2pContract.filters.DepositAdded(null); - const eventsDeposits = await p2pContract.queryFilter(filterDeposits); + // TODO: Remove this once we have a subgraph for rootstock + if (network === NetworkEnum.rootstock) return []; - if (!contract) p2pContract = getContract(); // get metamask provider contract - const depositList: { [key: string]: ValidDeposit } = {}; - - await Promise.all( - eventsDeposits.map(async (deposit) => { - // Get liquidity only for the selected token - if (deposit.args?.token != token) return null; - - const mappedBalance = await p2pContract.getBalance( - deposit.args?.seller, - token - ); - - const mappedPixTarget = await p2pContract.getPixTarget( - deposit.args?.seller, - token - ); - - let validDeposit: ValidDeposit | null = null; - - if (mappedBalance._hex) { - validDeposit = { - token: token, - blockNumber: deposit.blockNumber, - remaining: Number(formatEther(mappedBalance._hex)), - seller: deposit.args?.seller, - pixKey: Number(mappedPixTarget._hex), - }; + const body = { + query: ` + { + depositAddeds(where: { token: "${token}" }) { + seller + amount + blockTimestamp + blockNumber + } } + `, + }; - if (validDeposit) - depositList[deposit.args?.seller + token] = validDeposit; - }) + const depositLogs = await fetch(getNetworkSubgraphURL(network), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + // remove doubles from sellers list + const depositData = await depositLogs.json(); + const depositAddeds = depositData.data.depositAddeds; + const uniqueSellers = depositAddeds.reduce( + (acc: Record, deposit: any) => { + acc[deposit.seller] = true; + return acc; + }, + {} as Record ); + if (!contractInfo) { + // Get metamask provider contract + ({ abi, client } = await getContract(true)); + } + + const depositList: { [key: string]: ValidDeposit } = {}; + + const sellersList = Object.keys(uniqueSellers) as Address[]; + // Use multicall to batch all getBalance requests + const balanceCalls = sellersList.map((seller) => ({ + address: getP2PixAddress(network), + abi, + functionName: "getBalance", + args: [seller, token], + })); + + const balanceResults = await client.multicall({ + contracts: balanceCalls as any, + }); + + // Process results into the depositList + sellersList.forEach((seller, index) => { + const mappedBalance = balanceResults[index]; + + if (!mappedBalance.error && mappedBalance.result) { + const validDeposit: ValidDeposit = { + token, + blockNumber: 0, + remaining: Number(formatEther(mappedBalance.result as bigint)), + seller, + network, + participantID: "", + }; + depositList[seller + token] = validDeposit; + } + }); return Object.values(depositList); }; const getUnreleasedLockById = async ( - lockID: string + lockID: bigint ): Promise => { - const p2pContract = getContract(); - const pixData: Pix = { - pixKey: "", - }; + const { address, abi, client } = await getContract(); - const lock = await p2pContract.mapLocks(lockID); - - const pixTarget = lock.pixTarget; - const amount = formatEther(lock?.amount); - pixData.pixKey = String(Number(pixTarget)); - pixData.value = Number(amount); + const [ , , , amount, token, seller ] = await client.readContract({ + address, + abi, + functionName: "mapLocks", + args: [lockID], + }); return { - lockID: lockID, - pix: pixData, + lockID, + amount: Number(formatEther(amount)), + tokenAddress: token, + sellerAddress: seller, }; }; -export { getValidDeposits, getNetworksLiquidity, getUnreleasedLockById }; +export { + getValidDeposits, + getNetworksLiquidity, + getUnreleasedLockById, + getParticipantID, +}; diff --git a/src/blockchain/provider.ts b/src/blockchain/provider.ts index 08448e7..24ec20c 100644 --- a/src/blockchain/provider.ts +++ b/src/blockchain/provider.ts @@ -1,95 +1,62 @@ -import { useEtherStore } from "@/store/ether"; - -import p2pix from "@/utils/smart_contract_files/P2PIX.json"; - +import { p2PixAbi } from "./abi"; import { updateWalletStatus } from "./wallet"; +import { getProviderUrl, getP2PixAddress } from "./addresses"; import { - getProviderUrl, - isPossibleNetwork, - possibleChains, - network2Chain, - getP2PixAddress, -} from "./addresses"; + createPublicClient, + createWalletClient, + custom, + http, + PublicClient, + WalletClient, +} from "viem"; +import { sepolia, rootstock } from "viem/chains"; +import { useUser } from "@/composables/useUser"; -import { ethers } from "ethers"; +let walletClient: WalletClient | null = null; -const getProvider = ( - onlyAlchemyProvider: boolean = false -): ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider => { - const window_ = window as any; - const connection = window_.ethereum; - - if (!connection || onlyAlchemyProvider) - return new ethers.providers.JsonRpcProvider(getProviderUrl()); // alchemy provider - - return new ethers.providers.Web3Provider(connection); // metamask provider +const getPublicClient = (): PublicClient => { + const user = useUser(); + const rpcUrl = getProviderUrl(); + return createPublicClient({ + chain: + Number(user.networkName.value) === sepolia.id ? sepolia : rootstock, + transport: http(rpcUrl), + }); }; -const getContract = (onlyAlchemyProvider: boolean = false) => { - const provider = getProvider(onlyAlchemyProvider); - const signer = provider.getSigner(); - return new ethers.Contract(getP2PixAddress(), p2pix.abi, signer); +const getWalletClient = (): WalletClient | null => { + return walletClient; }; -const connectProvider = async (): Promise => { - const window_ = window as any; - const connection = window_.ethereum; - const provider = getProvider(); +const getContract = async (onlyRpcProvider = false) => { + const client = getPublicClient(); + const address = getP2PixAddress(); + const abi = p2PixAbi; + const wallet = onlyRpcProvider ? null : getWalletClient(); - if (!(provider instanceof ethers.providers.Web3Provider)) { - window.alert("Please, connect to metamask extension"); - return; + if (!client) { + throw new Error("Public client not initialized"); } + const [account] = wallet ? await wallet.getAddresses() : [null]; + + return { address, abi, client, wallet, account }; +}; + +const connectProvider = async (p: any): Promise => { + const user = useUser(); + const chain = + Number(user.networkName.value) === sepolia.id ? sepolia : rootstock; + + const [account] = await p!.request({ method: "eth_requestAccounts" }); + + walletClient = createWalletClient({ + account, + chain, + transport: custom(p), + }); + await updateWalletStatus(); - - listenToNetworkChange(connection); - listenToWalletChange(connection); }; -const listenToWalletChange = (connection: any): void => { - connection.on("accountsChanged", async () => { - console.log("Changed account!"); - updateWalletStatus(); - }); -}; - -const listenToNetworkChange = (connection: any) => { - const etherStore = useEtherStore(); - - connection.on("chainChanged", (networkChain: string) => { - console.log("Changed network!"); - - if (isPossibleNetwork(networkChain)) { - etherStore.setNetworkName(possibleChains[networkChain]); - updateWalletStatus(); - } else { - window.alert("Invalid chain!"); - } - }); -}; - -const requestNetworkChange = async (network: string): Promise => { - const etherStore = useEtherStore(); - if (!etherStore.walletAddress) return true; - - try { - const window_ = window as any; - await window_.ethereum.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: network2Chain[network] }], // chainId must be in hexadecimal numbers - }); - } catch { - return false; - } - - return true; -}; - -export { - getProvider, - getContract, - connectProvider, - listenToNetworkChange, - requestNetworkChange, -}; +export { getPublicClient, getWalletClient, getContract, connectProvider }; diff --git a/src/blockchain/sellerMethods.ts b/src/blockchain/sellerMethods.ts index 1fd1c0e..eac17a3 100644 --- a/src/blockchain/sellerMethods.ts +++ b/src/blockchain/sellerMethods.ts @@ -1,44 +1,88 @@ -import { getContract, getProvider } from "./provider"; +import { getContract, getPublicClient, getWalletClient } from "./provider"; import { getTokenAddress, getP2PixAddress } from "./addresses"; -import { parseEther } from "ethers/lib/utils"; +import { parseEther, toHex } from "viem"; +import { sepolia, rootstock } from "viem/chains"; -import { ethers } from "ethers"; +import { mockTokenAbi } from "./abi"; +import { useUser } from "@/composables/useUser"; +import { createParticipant } from "@/utils/bbPay"; +import type { Participant } from "@/utils/bbPay"; -import mockToken from "../utils/smart_contract_files/MockToken.json"; +const approveTokens = async (participant: Participant): Promise => { + const user = useUser(); + const publicClient = getPublicClient(); + const walletClient = getWalletClient(); -const approveTokens = async (tokenQty: string): Promise => { - const provider = getProvider(); - const signer = provider.getSigner(); + if (!publicClient || !walletClient) { + throw new Error("Clients not initialized"); + } - const tokenContract = new ethers.Contract( - getTokenAddress(), - mockToken.abi, - signer - ); + user.setSeller(participant); + const [account] = await walletClient.getAddresses(); - const apprv = await tokenContract.approve( - getP2PixAddress(), - parseEther(tokenQty) - ); + // Get token address + const tokenAddress = getTokenAddress(user.selectedToken.value); - await apprv.wait(); - return apprv; + // Check if the token is already approved + const allowance = await publicClient.readContract({ + address: tokenAddress, + abi: mockTokenAbi, + functionName: "allowance", + args: [account, getP2PixAddress()], + }); + + if ( allowance < parseEther(participant.offer.toString()) ) { + // Approve tokens + const chain = user.networkId.value === sepolia.id ? sepolia : rootstock; + const hash = await walletClient.writeContract({ + address: tokenAddress, + abi: mockTokenAbi, + functionName: "approve", + args: [getP2PixAddress(), parseEther(participant.offer.toString())], + account, + chain, + }); + + await publicClient.waitForTransactionReceipt({ hash }); + return true; + } + return true; }; -const addDeposit = async (tokenQty: string, pixKey: string): Promise => { - const p2pContract = getContract(); +const addDeposit = async (): Promise => { + const { address, abi, client } = await getContract(); + const walletClient = getWalletClient(); + const user = useUser(); - const deposit = await p2pContract.deposit( - getTokenAddress(), - parseEther(tokenQty), - pixKey, - true, - ethers.utils.formatBytes32String("") - ); + if (!walletClient) { + throw new Error("Wallet client not initialized"); + } - await deposit.wait(); + const [account] = await walletClient.getAddresses(); - return deposit; + const sellerId = await createParticipant(user.seller.value); + user.setSellerId(sellerId.id); + if (!sellerId.id) { + throw new Error("Failed to create participant"); + } + const chain = user.networkId.value === sepolia.id ? sepolia : rootstock; + const hash = await walletClient.writeContract({ + address, + abi, + functionName: "deposit", + args: [ + user.networkId.value + "-" + sellerId.id, + toHex("", { size: 32 }), + getTokenAddress(user.selectedToken.value), + parseEther(user.seller.value.offer.toString()), + true, + ], + account, + chain, + }); + + const receipt = await client.waitForTransactionReceipt({ hash }); + return receipt; }; export { approveTokens, addDeposit }; diff --git a/src/blockchain/wallet.ts b/src/blockchain/wallet.ts index d29afb9..34851ea 100644 --- a/src/blockchain/wallet.ts +++ b/src/blockchain/wallet.ts @@ -1,50 +1,48 @@ -import { useEtherStore } from "@/store/ether"; +import { formatEther, hexToString, type Address } from "viem"; +import { useUser } from "@/composables/useUser"; -import { getContract, getProvider } from "./provider"; -import { getTokenAddress, possibleChains } from "./addresses"; +import { getPublicClient, getWalletClient, getContract } from "./provider"; +import { getTokenAddress } from "./addresses"; -import mockToken from "@/utils/smart_contract_files/MockToken.json"; - -import { ethers, type Event, type BigNumber } from "ethers"; -import { formatEther } from "ethers/lib/utils"; -import { getValidDeposits } from "./events"; +import { getValidDeposits, getUnreleasedLockById } from "./events"; import type { ValidDeposit } from "@/model/ValidDeposit"; import type { WalletTransaction } from "@/model/WalletTransaction"; import type { UnreleasedLock } from "@/model/UnreleasedLock"; -import type { Pix } from "@/model/Pix"; +import { LockStatus } from "@/model/LockStatus"; +import { getNetworkSubgraphURL } from "@/model/NetworkEnum"; -const updateWalletStatus = async (): Promise => { - const etherStore = useEtherStore(); +export const updateWalletStatus = async (): Promise => { + const user = useUser(); - const provider = getProvider(); - const signer = provider.getSigner(); + const publicClient = getPublicClient(); + const walletClient = getWalletClient(); - const { chainId } = await provider.getNetwork(); - etherStore.setNetworkName(possibleChains[chainId]); + if (!publicClient || !walletClient) { + console.error("Client not initialized"); + return; + } - const mockTokenContract = new ethers.Contract( - getTokenAddress(), - mockToken.abi, - signer - ); + // Get balance + const [account] = await walletClient.getAddresses(); + const balance = await publicClient.getBalance({ address: account }); - const walletAddress = await provider.send("eth_requestAccounts", []); - const balance = await mockTokenContract.balanceOf(walletAddress[0]); - - etherStore.setBalance(formatEther(balance)); - etherStore.setWalletAddress(ethers.utils.getAddress(walletAddress[0])); + user.setWalletAddress(account); + user.setBalance(formatEther(balance)); }; -const listValidDepositTransactionsByWalletAddress = async ( - walletAddress: string +export const listValidDepositTransactionsByWalletAddress = async ( + walletAddress: Address ): Promise => { - const walletDeposits = await getValidDeposits(getTokenAddress()); - + const user = useUser(); + const walletDeposits = await getValidDeposits( + getTokenAddress(user.selectedToken.value), + user.networkName.value + ); if (walletDeposits) { return walletDeposits .filter((deposit) => deposit.seller == walletAddress) - .sort((a, b) => { + .sort((a: ValidDeposit, b: ValidDeposit) => { return b.blockNumber - a.blockNumber; }); } @@ -52,191 +50,431 @@ const listValidDepositTransactionsByWalletAddress = async ( return []; }; -const getLockStatus = async (id: [BigNumber]): Promise => { - const p2pContract = getContract(); - const res = await p2pContract.getLocksStatus([id]); - - return res[1][0]; +const getLockStatus = async (id: bigint): Promise => { + const { address, abi, client } = await getContract(); + const [ sortedIDs , status ] = await client.readContract({ + address, + abi, + functionName: "getLocksStatus", + args: [[id]], + }); + return status[0]; }; -const filterLockStatus = async ( - transactions: Event[] +export const listAllTransactionByWalletAddress = async ( + walletAddress: Address ): Promise => { - const txs = await Promise.all( - transactions.map(async (transaction) => { - const tx: WalletTransaction = { - token: transaction.args?.token ? transaction.args?.token : "", - blockNumber: transaction.blockNumber ? transaction.blockNumber : -1, - amount: transaction.args?.amount - ? Number(formatEther(transaction.args?.amount)) - : -1, - seller: transaction.args?.seller ? transaction.args?.seller : "", - buyer: transaction.args?.buyer ? transaction.args?.buyer : "", - event: transaction.event ? transaction.event : "", - lockStatus: - transaction.event == "LockAdded" - ? await getLockStatus(transaction.args?.lockID) - : -1, - transactionHash: transaction.transactionHash - ? transaction.transactionHash - : "", - transactionID: transaction.args?.lockID - ? String(transaction.args?.lockID) - : "", - }; + const user = useUser(); - return tx; - }) - ); + // Get the current network for the subgraph URL + const network = user.networkName.value; - return txs; -}; + // Query subgraph for all relevant transactions + const subgraphQuery = { + query: ` + { + depositAddeds(where: {seller: "${walletAddress.toLowerCase()}"}) { + id + seller + token + amount + blockTimestamp + blockNumber + transactionHash + } + lockAddeds(where: {buyer: "${walletAddress.toLowerCase()}"}) { + buyer + lockID + seller + amount + blockTimestamp + blockNumber + transactionHash + } + lockReleaseds(where: {buyer: "${walletAddress.toLowerCase()}"}) { + buyer + lockId + blockTimestamp + blockNumber + transactionHash + } + depositWithdrawns(where: {seller: "${walletAddress.toLowerCase()}"}) { + seller + token + amount + blockTimestamp + blockNumber + transactionHash + } + } + `, + }; -const listAllTransactionByWalletAddress = async ( - walletAddress: string -): Promise => { - const p2pContract = getContract(true); + const response = await fetch(getNetworkSubgraphURL(network), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(subgraphQuery), + }); - const filterDeposits = p2pContract.filters.DepositAdded([walletAddress]); - const eventsDeposits = await p2pContract.queryFilter(filterDeposits); + const data = await response.json(); + // Convert all transactions to common WalletTransaction format + const transactions: WalletTransaction[] = []; - const filterAddedLocks = p2pContract.filters.LockAdded([walletAddress]); - const eventsAddedLocks = await p2pContract.queryFilter(filterAddedLocks); + // Process deposit added events + if (data.data?.depositAddeds) { + for (const deposit of data.data.depositAddeds) { + transactions.push({ + token: deposit.token, + blockNumber: parseInt(deposit.blockNumber), + amount: parseFloat(formatEther(BigInt(deposit.amount))), + seller: deposit.seller, + buyer: "", + event: "DepositAdded", + lockStatus: undefined, + transactionHash: deposit.transactionHash, + }); + } + } - const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]); - const eventsReleasedLocks = await p2pContract.queryFilter( - filterReleasedLocks - ); + // Process lock added events + if (data.data?.lockAddeds) { + for (const lock of data.data.lockAddeds) { + // Get lock status from the contract + const lockStatus = await getLockStatus(BigInt(lock.lockID)); - const filterWithdrawnDeposits = p2pContract.filters.DepositWithdrawn([ - walletAddress, - ]); - const eventsWithdrawnDeposits = await p2pContract.queryFilter( - filterWithdrawnDeposits - ); + transactions.push({ + token: lock.token, + blockNumber: parseInt(lock.blockNumber), + amount: parseFloat(formatEther(BigInt(lock.amount))), + seller: lock.seller, + buyer: lock.buyer, + event: "LockAdded", + lockStatus: lockStatus, + transactionHash: lock.transactionHash, + transactionID: lock.lockID.toString(), + }); + } + } - const lockStatusFiltered = await filterLockStatus( - [ - ...eventsDeposits, - ...eventsAddedLocks, - ...eventsReleasedLocks, - ...eventsWithdrawnDeposits, - ].sort((a, b) => { - return b.blockNumber - a.blockNumber; - }) - ); + // Process lock released events + if (data.data?.lockReleaseds) { + for (const release of data.data.lockReleaseds) { + transactions.push({ + token: undefined, // Subgraph doesn't provide token in this event, we could enhance this later + blockNumber: parseInt(release.blockNumber), + amount: -1, // Amount not available in this event + seller: "", + buyer: release.buyer, + event: "LockReleased", + lockStatus: undefined, + transactionHash: release.transactionHash, + transactionID: release.lockId.toString(), + }); + } + } - return lockStatusFiltered; + // Process deposit withdrawn events + if (data.data?.depositWithdrawns) { + for (const withdrawal of data.data.depositWithdrawns) { + transactions.push({ + token: withdrawal.token, + blockNumber: parseInt(withdrawal.blockNumber), + amount: parseFloat(formatEther(BigInt(withdrawal.amount))), + seller: withdrawal.seller, + buyer: "", + event: "DepositWithdrawn", + lockStatus: undefined, + transactionHash: withdrawal.transactionHash, + }); + } + } + + // Sort transactions by block number (newest first) + return transactions.sort((a, b) => b.blockNumber - a.blockNumber); }; // get wallet's release transactions -const listReleaseTransactionByWalletAddress = async ( - walletAddress: string -): Promise => { - const p2pContract = getContract(true); +export const listReleaseTransactionByWalletAddress = async ( + walletAddress: Address +) => { + const user = useUser(); + const network = user.networkName.value; - const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]); - const eventsReleasedLocks = await p2pContract.queryFilter( - filterReleasedLocks - ); - - return eventsReleasedLocks.sort((a, b) => { - return b.blockNumber - a.blockNumber; - }); -}; - -const listLockTransactionByWalletAddress = async ( - walletAddress: string -): Promise => { - const p2pContract = getContract(true); - - const filterAddedLocks = p2pContract.filters.LockAdded([walletAddress]); - const eventsReleasedLocks = await p2pContract.queryFilter(filterAddedLocks); - - return eventsReleasedLocks.sort((a, b) => { - return b.blockNumber - a.blockNumber; - }); -}; - -const listLockTransactionBySellerAddress = async ( - sellerAddress: string -): Promise => { - const p2pContract = getContract(true); - - const filterAddedLocks = p2pContract.filters.LockAdded(); - const eventsReleasedLocks = await p2pContract.queryFilter(filterAddedLocks); - - return eventsReleasedLocks.filter((lock) => - lock.args?.seller - .toHexString() - .substring(3) - .includes(sellerAddress.substring(2).toLowerCase()) - ); -}; - -const checkUnreleasedLock = async ( - walletAddress: string -): Promise => { - const p2pContract = getContract(); - const pixData: Pix = { - pixKey: "", + // Query subgraph for release transactions + const subgraphQuery = { + query: ` + { + lockReleaseds(where: {buyer: "${walletAddress.toLowerCase()}"}) { + buyer + lockId + e2eId + blockTimestamp + blockNumber + transactionHash + } + } + `, }; - const addedLocks = await listLockTransactionByWalletAddress(walletAddress); - const lockStatus = await p2pContract.getLocksStatus( - addedLocks.map((lock) => lock.args?.lockID) - ); - const unreleasedLockId = lockStatus[1].findIndex( - (lockStatus: number) => lockStatus == 1 - ); + // Fetch data from subgraph + const response = await fetch(getNetworkSubgraphURL(network), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(subgraphQuery), + }); - if (unreleasedLockId != -1) { - const _lockID = lockStatus[0][unreleasedLockId]; - const lock = await p2pContract.mapLocks(_lockID); + const data = await response.json(); - const pixTarget = lock.pixTarget; - const amount = formatEther(lock?.amount); - pixData.pixKey = String(Number(pixTarget)); - pixData.value = Number(amount); + // Process the subgraph response into the same format as the previous implementation + if (!data.data?.lockReleaseds) { + return []; + } - return { - lockID: _lockID, - pix: pixData, - }; + // Transform the subgraph data to match the event log decode format + return data.data.lockReleaseds + .sort((a: any, b: any) => { + return parseInt(b.blockNumber) - parseInt(a.blockNumber); + }) + .map((release: any) => { + try { + // Create a structure similar to the decoded event log + return { + eventName: "LockReleased", + args: { + buyer: release.buyer, + lockID: BigInt(release.lockId), + e2eId: release.e2eId, + }, + // Add any other necessary fields to match the original return format + blockNumber: BigInt(release.blockNumber), + transactionHash: release.transactionHash, + }; + } catch (error) { + console.error("Error processing subgraph data", error); + return null; + } + }) + .filter((decoded: any) => decoded !== null); +}; + +const listLockTransactionByWalletAddress = async (walletAddress: Address) => { + const user = useUser(); + const network = user.networkName.value; + + // Query subgraph for lock added transactions + const subgraphQuery = { + query: ` + { + lockAddeds(where: {buyer: "${walletAddress.toLowerCase()}"}) { + buyer + lockID + seller + amount + blockTimestamp + blockNumber + transactionHash + } + } + `, + }; + + try { + // Fetch data from subgraph + const response = await fetch(getNetworkSubgraphURL(network), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(subgraphQuery), + }); + + const data = await response.json(); + + if (!data.data?.lockAddeds) { + return []; + } + + // Transform the subgraph data to match the event log decode format + return data.data.lockAddeds + .sort((a: any, b: any) => { + return parseInt(b.blockNumber) - parseInt(a.blockNumber); + }) + .map((lock: any) => { + try { + // Create a structure similar to the decoded event log + return { + eventName: "LockAdded", + args: { + buyer: lock.buyer, + lockID: BigInt(lock.lockID), + seller: lock.seller, + token: lock.token, + amount: BigInt(lock.amount), + }, + // Add other necessary fields to match the original format + blockNumber: BigInt(lock.blockNumber), + transactionHash: lock.transactionHash, + }; + } catch (error) { + console.error("Error processing subgraph data", error); + return null; + } + }) + .filter((decoded: any) => decoded !== null); + } catch (error) { + console.error("Error fetching from subgraph:", error); } }; -const getActiveLockAmount = async (walletAddress: string): Promise => { - const p2pContract = getContract(); +const listLockTransactionBySellerAddress = async (sellerAddress: Address) => { + const user = useUser(); + const network = user.networkName.value; + + // Query subgraph for lock added transactions where seller matches + const subgraphQuery = { + query: ` + { + lockAddeds(where: {seller: "${sellerAddress.toLowerCase()}"}) { + buyer + lockID + seller + token + amount + blockTimestamp + blockNumber + transactionHash + } + } + `, + }; + + try { + // Fetch data from subgraph + const response = await fetch(getNetworkSubgraphURL(network), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(subgraphQuery), + }); + + const data = await response.json(); + + if (!data.data?.lockAddeds) { + return []; + } + + // Transform the subgraph data to match the event log decode format + return data.data.lockAddeds + .sort((a: any, b: any) => { + return parseInt(b.blockNumber) - parseInt(a.blockNumber); + }) + .map((lock: any) => { + try { + // Create a structure similar to the decoded event log + return { + eventName: "LockAdded", + args: { + buyer: lock.buyer, + lockID: BigInt(lock.lockID), + seller: lock.seller, + token: lock.token, + amount: BigInt(lock.amount), + }, + // Add other necessary fields to match the original format + blockNumber: BigInt(lock.blockNumber), + transactionHash: lock.transactionHash, + }; + } catch (error) { + console.error("Error processing subgraph data", error); + return null; + } + }) + .filter((decoded: any) => decoded !== null); + } catch (error) { + console.error("Error fetching from subgraph:", error); + return []; + } +}; + +export const checkUnreleasedLock = async ( + walletAddress: Address +): Promise => { + const { address, abi, client } = await getContract(); + const addedLocks = await listLockTransactionByWalletAddress(walletAddress); + + if (!addedLocks.length) return undefined; + + const lockIds = addedLocks.map((lock: any) => lock.args.lockID); + + const [ sortedIDs, status ] = await client.readContract({ + address, + abi, + functionName: "getLocksStatus", + args: [lockIds], + }); + + const unreleasedLockId = status.findIndex( + (status: LockStatus) => status == LockStatus.Active + ); + + if (unreleasedLockId !== -1) + return getUnreleasedLockById(sortedIDs[unreleasedLockId]); +}; + +export const getActiveLockAmount = async ( + walletAddress: Address +): Promise => { + const { address, abi, client } = await getContract(true); const lockSeller = await listLockTransactionBySellerAddress(walletAddress); - const lockStatus = await p2pContract.getLocksStatus( - lockSeller.map((lock) => lock.args?.lockID) + if (!lockSeller.length) return 0; + + const lockIds = lockSeller.map((lock: any) => lock.args.lockID); + + const [ sortedIDs, status ] = await client.readContract({ + address, + abi, + functionName: "getLocksStatus", + args: [lockIds], + }); + + const mapLocksRequests = status.map((id: LockStatus) => + client.readContract({ + address: address, + abi, + functionName: "mapLocks", + args: [BigInt(id)], + }) ); - const activeLockAmount = await lockStatus[1].reduce( - async (sumValue: Promise, currentStatus: number, index: number) => { - const currValue = await sumValue; - let valueToSum = 0; + const mapLocksResults = await client.multicall({ + contracts: mapLocksRequests as any, + }); - if (currentStatus == 1) { - const lock = await p2pContract.mapLocks(lockStatus[0][index]); - valueToSum = Number(formatEther(lock?.amount)); - } - - return currValue + valueToSum; - }, - Promise.resolve(0) - ); - - return activeLockAmount; + return mapLocksResults.reduce((total: number, lock: any, index: number) => { + if (status[index] === 1) { + return total + Number(formatEther(lock.amount)); + } + return total; + }, 0); }; -export { - updateWalletStatus, - listValidDepositTransactionsByWalletAddress, - listAllTransactionByWalletAddress, - listReleaseTransactionByWalletAddress, - checkUnreleasedLock, - getActiveLockAmount, +export const getSellerParticipantId = async ( + sellerAddress: Address, + tokenAddress: Address +): Promise => { + const { address, abi, client } = await getContract(); + + const participantId = await client.readContract({ + address, + abi, + functionName: "getPixTarget", + args: [sellerAddress, tokenAddress], + }); + return hexToString(participantId); }; diff --git a/src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue b/src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue index 92ec39c..2f1f15d 100644 --- a/src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue +++ b/src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue @@ -8,8 +8,7 @@ import { import CustomButton from "@/components/CustomButton/CustomButton.vue"; import type { ValidDeposit } from "@/model/ValidDeposit"; import type { WalletTransaction } from "@/model/WalletTransaction"; -import { useEtherStore } from "@/store/ether"; -import { storeToRefs } from "pinia"; +import { useUser } from "@/composables/useUser"; import { onMounted, ref, watch } from "vue"; import ListingComponent from "../ListingComponent/ListingComponent.vue"; @@ -19,8 +18,8 @@ const props = defineProps<{ isCurrentStep: boolean; }>(); -const etherStore = useEtherStore(); -const { walletAddress } = storeToRefs(etherStore); +const user = useUser(); +const { walletAddress } = useUser(); const lastWalletTransactions = ref([]); const depositList = ref([]); @@ -29,7 +28,7 @@ const activeLockAmount = ref(0); // methods const getWalletTransactions = async () => { - etherStore.setLoadingWalletTransactions(true); + user.setLoadingWalletTransactions(true); if (walletAddress.value) { const walletDeposits = await listValidDepositTransactionsByWalletAddress( walletAddress.value @@ -48,20 +47,20 @@ const getWalletTransactions = async () => { lastWalletTransactions.value = allUserTransactions; } } - etherStore.setLoadingWalletTransactions(false); + user.setLoadingWalletTransactions(false); }; const callWithdraw = async (amount: string) => { if (amount) { - etherStore.setLoadingWalletTransactions(true); - const withdraw = await withdrawDeposit(amount); + user.setLoadingWalletTransactions(true); + const withdraw = await withdrawDeposit(amount, user.selectedToken.value); if (withdraw) { console.log("Saque realizado!"); await getWalletTransactions(); } else { console.log("Não foi possível realizar o saque!"); } - etherStore.setLoadingWalletTransactions(false); + user.setLoadingWalletTransactions(false); } }; @@ -86,19 +85,21 @@ onMounted(async () => { para a sua carteira! -
+

Tokens recebidos

-

{{ props.tokenAmount }} BRZ

+

+ {{ props.tokenAmount }} {{ user.selectedToken }} +

Não encontrou os tokens?
Clique no botão abaixo para
- cadastrar o BRZ em sua carteira. + cadastrar o {{ user.selectedToken }} em sua carteira.

@@ -143,42 +144,13 @@ p { .text { @apply text-white text-center; } -.blur-container-row { - @apply flex flex-row justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 w-1/3; -} - -.blur-container { - @apply flex w-full max-w-xs md:max-w-lg flex-col justify-center items-center px-8 py-6 gap-4 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10; -} .last-release-info { @apply font-medium text-base text-gray-900; } -input[type="number"] { - -moz-appearance: textfield; -} - input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; } - -.lg-view { - display: inline-block; -} - -.sm-view { - display: none; -} - -@media screen and (max-width: 500px) { - .lg-view { - display: none; - } - - .sm-view { - display: inline-block; - } -} diff --git a/src/components/BuyConfirmedComponent/__tests__/BuyConfirmedComponent.spec.ts b/src/components/BuyConfirmedComponent/__tests__/BuyConfirmedComponent.spec.ts deleted file mode 100644 index f860cf5..0000000 --- a/src/components/BuyConfirmedComponent/__tests__/BuyConfirmedComponent.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { mount } from "@vue/test-utils"; -import BuyConfirmedComponent from "../BuyConfirmedComponent.vue"; -import { createPinia, setActivePinia } from "pinia"; - -describe("BuyConfirmedComponent.vue", async () => { - beforeEach(() => { - setActivePinia(createPinia()); - }); - - const wrapper = mount(BuyConfirmedComponent, { - props: { - tokenAmount: 1, - isCurrentStep: false, - }, - }); - - // test("Test component Header Text", () => { - // expect(wrapper.html()).toContain("Os tokens já foram transferidos"); - // expect(wrapper.html()).toContain("para a sua carteira!"); - // }); - - // test("Test component Container Text", () => { - // expect(wrapper.html()).toContain("Tokens recebidos"); - // expect(wrapper.html()).toContain("BRZ"); - // expect(wrapper.html()).toContain("Não encontrou os tokens?"); - // expect(wrapper.html()).toContain("Clique no botão abaixo para"); - // expect(wrapper.html()).toContain("cadastrar o BRZ em sua carteira."); - // }); - - test("Test makeAnotherTransactionEmit", async () => { - wrapper.vm.$emit("makeAnotherTransaction"); - - await wrapper.vm.$nextTick(); - - expect(wrapper.emitted("makeAnotherTransaction")).toBeTruthy(); - }); -}); diff --git a/src/components/CustomAlert/CustomAlert.vue b/src/components/CustomAlert/CustomAlert.vue index b49e4ec..0d70d52 100644 --- a/src/components/CustomAlert/CustomAlert.vue +++ b/src/components/CustomAlert/CustomAlert.vue @@ -38,9 +38,9 @@ switch (props.type) {