diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml index 293d3c5d42..0321d1f609 100644 --- a/.github/workflows/changesets.yml +++ b/.github/workflows/changesets.yml @@ -63,6 +63,7 @@ jobs: with: createGithubReleases: ${{ github.ref == 'refs/heads/main' }} publish: pnpm changeset:publish + version: pnpm changeset:version env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index bc4ad92353..7590ff0378 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -85,12 +85,7 @@ jobs: - name: Bench types if: matrix.version != '5.0.4' - run: pnpm typebench - - # Redundant with `pnpm typecheck` - # If Vitest adds special features in the future, e.g. type coverage, can add this back! - # - name: Test types - # run: pnpm test:typecheck + run: pnpm bench:types test: name: Test diff --git a/package.json b/package.json index cacf44379c..b5de87979c 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "type": "module", "scripts": { "bench": "vitest bench", + "bench:types": "TYPES=true vitest -c ./test/vitest.config.ts bench-d.ts", "build": "pnpm clean && pnpm build:cjs && pnpm build:esm && pnpm build:types", "build:cjs": "pnpm build:trustedSetups:start && tsc --project ./tsconfig.build.json --module commonjs --outDir ./src/_cjs --removeComments --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./src/_cjs/package.json && pnpm build:trustedSetups:end", "build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./src/_esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./src/_esm/package.json", @@ -22,7 +23,7 @@ "lint:repo": "sherif", "lint:unused": "pnpm clean && knip", "postinstall": "git submodule update --init --recursive && pnpm contracts:build", - "preinstall": "npx only-allow pnpm", + "preinstall": "pnpx only-allow pnpm", "prepare": "pnpm simple-git-hooks", "prepublishOnly": "bun scripts/prepublishOnly.ts", "size": "size-limit", @@ -39,7 +40,6 @@ "test:env:vite": "pnpm --filter test-vite test", "test:typecheck": "SKIP_GLOBAL_SETUP=true vitest --typecheck.only -c ./test/vitest.config.ts", "test:ui": "vitest dev -c ./test/vitest.config.ts --ui", - "typebench": "tsx test/scripts/typebench.ts --benchPercentThreshold 10 --benchErrorOnThresholdExceeded", "typecheck": "tsc --noEmit", "vectors": "bun test vectors/**/*.test.ts", "vectors:generate": "bun vectors/generate.ts", @@ -47,7 +47,7 @@ }, "devDependencies": { "@arethetypeswrong/cli": "^0.15.3", - "@arktype/attest": "0.7.5", + "@arktype/attest": "0.8.0", "@biomejs/biome": "^1.8.0", "@changesets/changelog-github": "^0.4.5", "@changesets/cli": "^2.23.2", @@ -67,7 +67,6 @@ "sherif": "^0.8.4", "simple-git-hooks": "^2.8.1", "size-limit": "^11.1.2", - "tsx": "^4.11.0", "typescript": "5.5.2", "vitest": "^1.0.4" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5d6b0d039..73f7b08eb4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^0.15.3 version: 0.15.3 '@arktype/attest': - specifier: 0.7.5 - version: 0.7.5(typescript@5.5.2) + specifier: 0.8.0 + version: 0.8.0(typescript@5.5.2) '@biomejs/biome': specifier: ^1.8.0 version: 1.8.0 @@ -71,9 +71,6 @@ importers: size-limit: specifier: ^11.1.2 version: 11.1.2 - tsx: - specifier: ^4.11.0 - version: 4.11.0 typescript: specifier: 5.5.2 version: 5.5.2 @@ -156,7 +153,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -169,7 +166,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -182,7 +179,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -195,7 +192,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -214,7 +211,7 @@ importers: version: 18.2.0(react@18.2.0) viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: '@types/react': specifier: ^18.0.27 @@ -242,7 +239,7 @@ importers: version: 18.2.0(react@18.2.0) viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: '@types/react': specifier: ^18.0.27 @@ -264,7 +261,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -277,7 +274,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -296,7 +293,7 @@ importers: version: 18.2.0(react@18.2.0) viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: '@types/react': specifier: ^18.0.27 @@ -318,7 +315,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -331,7 +328,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -344,7 +341,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -357,7 +354,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -404,7 +401,7 @@ importers: version: 18.2.0(react@18.2.0) viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: '@types/react': specifier: ^18.0.27 @@ -426,7 +423,7 @@ importers: dependencies: viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: typescript: specifier: ^5.0.3 @@ -445,7 +442,7 @@ importers: version: 18.2.0(react@18.2.0) viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: '@types/react': specifier: ^18.0.27 @@ -479,7 +476,7 @@ importers: version: 18.2.0(react@18.2.0) viem: specifier: latest - version: 2.16.0(typescript@5.4.2)(zod@3.22.4) + version: 2.16.2(typescript@5.4.2)(zod@3.22.4) devDependencies: '@types/react': specifier: ^18.0.27 @@ -569,23 +566,23 @@ packages: resolution: {integrity: sha512-FYp6GBAgsNz81BkfItRz8RLZO03w5+BaeiPma1uCfmxTnxbtuMrI/dbzGiOk8VghO108uFI0oJo0OkewdSHw7g==} engines: {node: '>=18'} - '@arktype/attest@0.7.5': - resolution: {integrity: sha512-ZOF9uqLbvoVO6RHhlByJEBBj5qhWLpaCK/wWa5guD1OQR1/a7JZ9jCrDAcaASt6tYBA3dGhDerXhc7FcDWlRQw==} + '@arktype/attest@0.8.0': + resolution: {integrity: sha512-wxQ8PdXSrlQyHzlQeXiMMARumAS4whpuvvqV+DWWDECAhrsyhV0yixAavapz1X7qu8253cCiF6h/dabpGYAtpw==} hasBin: true peerDependencies: typescript: '*' - '@arktype/fs@0.0.19': - resolution: {integrity: sha512-ZEiSc6DgJANSgMTee9lueumCH/3gIikJWT8wlN8CyVk/IDFKFbJb3/BHj906Aw+APvCc8oyvu+2Hanshkgh4Bg==} + '@arktype/fs@0.0.20': + resolution: {integrity: sha512-WnoIFrhiDKnWixd7xmcvFTlP7ZVReT7j37nTbCpieUCsVaUldb38pgQjxdvlJN40UL3kkjxyiYIRmc7BOvgy1A==} - '@arktype/schema@0.1.2': - resolution: {integrity: sha512-ggvxs5P0toqd/4/XK76URQrtyOYpbYcLhirEZeTso6FxkloPa0lT+whPg7DNQj5qi2OQXLUHBYKMx9DOb13ViQ==} + '@arktype/schema@0.1.18': + resolution: {integrity: sha512-6xMboHvnO3NtgYNP160PmghElUDpKe/aDMqH2hRRHoMb1Nh0bPilDfr9LJnXQEwfA5hDguqRM+vifOKkROtOLA==} - '@arktype/util@0.0.38': - resolution: {integrity: sha512-IvYMGnkUASJllRk3mdBVgckomKx2LNsDTrWCxz04EBK1OuU+4fJ/smSjxgZVWfopNXZds9sHNxZgTJOIw7GvJw==} + '@arktype/util@0.0.49': + resolution: {integrity: sha512-ptlPUDZ8EECx23S7OjQnMulUSt8lmhxq5pQXmiyMlVt9g9EhUOVpdFrNqSCntFURtennxwFDJaYa+7rKQrGrew==} - '@arktype/util@0.0.41': - resolution: {integrity: sha512-0YURzJ42v+lhlP1t5Dj90YezETRTCdFU0oM4xMVpYsmPx/DHJzr9n7AX1QPAlYWH4wY7hYY3gwai3O+8VntPgw==} + '@arktype/util@0.0.51': + resolution: {integrity: sha512-lukmZcbSVI27ZJ4uJA7ztCKM5OligUfdTrr0E6k+F0tzz9iSEcplS0KZbVD2WfrLL3HXNKBE6g/w3nhYMAMoqw==} '@babel/code-frame@7.24.6': resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} @@ -2281,6 +2278,11 @@ packages: '@typescript/vfs@1.5.0': resolution: {integrity: sha512-AJS307bPgbsZZ9ggCT3wwpg3VbTKMFNHfaY/uF0ahSkYYrPF2dSSKDNIDIQAHm9qJqbLvCsSJH7yN4Vs/CsMMg==} + '@typescript/vfs@1.5.3': + resolution: {integrity: sha512-OSZ/o3wwD5VPZVdGGsXWk7sRGRtwrGnqA4zwmb33FTs7Wxmad0QTkQCbaNyqWA8hL09TCwAthdp8yjFA5G1lvw==} + peerDependencies: + typescript: '*' + '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -2594,8 +2596,8 @@ packages: arity-n@1.0.4: resolution: {integrity: sha512-fExL2kFDC1Q2DUOx3whE/9KoN66IzkY4b4zUHUBFM1ojEYjZZYDcUW3bek/ufGionX9giIKDC5redH2IlGqcQQ==} - arktype@2.0.0-dev.11: - resolution: {integrity: sha512-k+WVQoHsHsTyTiVQkO201mxLQxyXHmy3buJW8TXLOkr4X2yOUCp0K1SBscuG9OEJoc8MjpvoIharjPHEkFI7kg==} + arktype@2.0.0-dev.26: + resolution: {integrity: sha512-L7JkKHPkvEoDRKhtXyrCQcHast2oXFo7sOX1SZ3GSbIFJcEnTRRW12lFvH8M4fFR589CaOE9LleHMg9jZFR2TA==} array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} @@ -3565,9 +3567,6 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.7.5: - resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} - get-uri@6.0.3: resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} engines: {node: '>= 14'} @@ -5165,9 +5164,6 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -5737,11 +5733,6 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tsx@4.11.0: - resolution: {integrity: sha512-vzGGELOgAupsNVssAmZjbUDfdm/pWP4R+Kg8TVdsonxbXk0bEpE1qh0yV6/QxUVXaVlNemgcPajGdJJ82n3stg==} - engines: {node: '>=18.0.0'} - hasBin: true - tty-table@4.2.3: resolution: {integrity: sha512-Fs15mu0vGzCrj8fmJNP7Ynxt5J7praPXqFN0leZeZBXJwkMxv9cb2D454k1ltrtUSJbZ4yH4e0CynsHLxmUfFA==} engines: {node: '>=8.0.0'} @@ -6007,8 +5998,8 @@ packages: vfile@6.0.1: resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} - viem@2.16.0: - resolution: {integrity: sha512-qXakKfshaDOiQFgb3MgROKDa4bfr095GMUqrD2WN6UMdzH7WtlAYJ65vnrpoXpny9jXAyNoirEJeBBUF9KFNIQ==} + viem@2.16.2: + resolution: {integrity: sha512-qor3v1cJFR3jcPtcJxPbKfKURAH2agNf2IWZIaSReV6teNLERiu4Sr7kbqpkIeTAEpiDCVQwg336M+mub1m+pg==} peerDependencies: typescript: '>=5.0.4' peerDependenciesMeta: @@ -6352,26 +6343,26 @@ snapshots: typescript: 5.3.3 validate-npm-package-name: 5.0.1 - '@arktype/attest@0.7.5(typescript@5.5.2)': + '@arktype/attest@0.8.0(typescript@5.5.2)': dependencies: - '@arktype/fs': 0.0.19 - '@arktype/util': 0.0.41 + '@arktype/fs': 0.0.20 + '@arktype/util': 0.0.49 '@typescript/analyze-trace': 0.10.1 - '@typescript/vfs': 1.5.0 - arktype: 2.0.0-dev.11 + '@typescript/vfs': 1.5.3(typescript@5.5.2) + arktype: 2.0.0-dev.26 typescript: 5.5.2 transitivePeerDependencies: - supports-color - '@arktype/fs@0.0.19': {} + '@arktype/fs@0.0.20': {} - '@arktype/schema@0.1.2': + '@arktype/schema@0.1.18': dependencies: - '@arktype/util': 0.0.38 + '@arktype/util': 0.0.51 - '@arktype/util@0.0.38': {} + '@arktype/util@0.0.49': {} - '@arktype/util@0.0.41': {} + '@arktype/util@0.0.51': {} '@babel/code-frame@7.24.6': dependencies: @@ -8073,6 +8064,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript/vfs@1.5.3(typescript@5.5.2)': + dependencies: + debug: 4.3.5 + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color + '@ungap/structured-clone@1.2.0': {} '@vanilla-extract/babel-plugin-debug-ids@1.0.6': @@ -8730,10 +8728,10 @@ snapshots: arity-n@1.0.4: {} - arktype@2.0.0-dev.11: + arktype@2.0.0-dev.26: dependencies: - '@arktype/schema': 0.1.2 - '@arktype/util': 0.0.38 + '@arktype/schema': 0.1.18 + '@arktype/util': 0.0.51 array-buffer-byte-length@1.0.1: dependencies: @@ -9819,10 +9817,6 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-tsconfig@4.7.5: - dependencies: - resolve-pkg-maps: 1.0.0 - get-uri@6.0.3: dependencies: basic-ftp: 5.0.5 @@ -11840,8 +11834,6 @@ snapshots: resolve-from@5.0.0: {} - resolve-pkg-maps@1.0.0: {} - resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -12436,13 +12428,6 @@ snapshots: tslib@2.6.2: {} - tsx@4.11.0: - dependencies: - esbuild: 0.20.2 - get-tsconfig: 4.7.5 - optionalDependencies: - fsevents: 2.3.3 - tty-table@4.2.3: dependencies: chalk: 4.1.2 @@ -12714,7 +12699,7 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - viem@2.16.0(typescript@5.4.2)(zod@3.22.4): + viem@2.16.2(typescript@5.4.2)(zod@3.22.4): dependencies: '@adraffy/ens-normalize': 1.10.0 '@noble/curves': 1.2.0 diff --git a/site/pages/experimental/erc7715/issuePermissions.mdx b/site/pages/experimental/erc7715/grantPermissions.mdx similarity index 56% rename from site/pages/experimental/erc7715/issuePermissions.mdx rename to site/pages/experimental/erc7715/grantPermissions.mdx index 819fc902ea..35e1a217fa 100644 --- a/site/pages/experimental/erc7715/issuePermissions.mdx +++ b/site/pages/experimental/erc7715/grantPermissions.mdx @@ -2,7 +2,7 @@ description: Request permissions from a wallet to perform actions on behalf of a user. --- -# issuePermissions +# grantPermissions Request permissions from a wallet to perform actions on behalf of a user. @@ -20,16 +20,23 @@ This is an experimental action that is not supported in most wallets. It is reco import { parseEther } from 'viem' import { account, walletClient } from './config' -const result = await walletClient.issuePermissions({ // [!code focus:99] +const result = await walletClient.grantPermissions({ // [!code focus:99] account, expiry: 1716846083638, permissions: [ { - type: 'native-token-limit', + type: 'native-token-transfer', data: { - amount: parseEther('0.5'), + ticker: 'ETH', }, - required: true, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + ], }, ], }) @@ -54,7 +61,7 @@ export const [account] = await walletClient.getAddresses() ## Returns -`IssuePermissionsReturnType` +`GrantPermissionsReturnType` Response from the wallet after issuing permissions. @@ -70,16 +77,23 @@ The Account to scope the permissions to. import { parseEther } from 'viem' import { account, walletClient } from './config' -const result = await walletClient.issuePermissions({ +const result = await walletClient.grantPermissions({ account, // [!code focus] expiry: 1716846083638, permissions: [ { - type: 'native-token-limit', + type: 'native-token-transfer', data: { - amount: parseEther('0.5'), + ticker: 'ETH', }, - required: true, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + ], }, ], }) @@ -95,16 +109,23 @@ The timestamp (in seconds) when the permissions will expire. import { parseEther } from 'viem' import { account, walletClient } from './config' -const result = await walletClient.issuePermissions({ +const result = await walletClient.grantPermissions({ account, expiry: 1716846083638, // [!code focus] permissions: [ { - type: 'native-token-limit', + type: 'native-token-transfer', data: { - amount: parseEther('0.5'), + ticker: 'ETH', }, - required: true, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + ], }, ], }) @@ -114,24 +135,31 @@ const result = await walletClient.issuePermissions({ - **Type:** `Permission[]` -Set of permissions to grant to the user. +Set of Permissions & Policies to grant to the user. ```ts twoslash // @noErrors import { parseEther } from 'viem' import { account, walletClient } from './config' -const result = await walletClient.issuePermissions({ +const result = await walletClient.grantPermissions({ account, expiry: 1716846083638, - permissions: [ // [!code focus:99] - { - type: 'native-token-limit', - data: { - amount: parseEther('0.5'), - }, - required: true, - }, + permissions: [ // [!code focus:19] + { + type: 'native-token-transfer', + data: { + ticker: 'ETH', + }, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + ], + }, { type: ' // ^| @@ -140,6 +168,30 @@ const result = await walletClient.issuePermissions({ }) ``` +:::tip +The `type` property is constrained to the canonical set of [Permission & Policy types as +defined in ERC-7715](https://github.com/pedrouid/ERCs/blob/19c16341c57f6ac8770cb778d60845dcf30f6a40/ERCS/erc-7715.md#permissions), however, consumers can utilize a `custom` property on `type` as an escape hatch to use custom Permission or Policy types: + +```ts twoslash +// @noErrors +import { parseEther } from 'viem' +import { account, walletClient } from './config' + +const result = await walletClient.grantPermissions({ + account, + expiry: 1716846083638, + permissions: [ + { + type: { custom: 'example' }, // [!code focus] + data: { + value: '0xdeadbeef', + } + } + ], +}) +``` +::: + ### signer - **Type:** `Signer | undefined` @@ -150,7 +202,7 @@ Custom signer type to scope the permissions to. import { parseEther } from 'viem' import { account, walletClient } from './config' -const result = await walletClient.issuePermissions({ +const result = await walletClient.grantPermissions({ expiry: 1716846083638, permissions: [ { diff --git a/site/sidebar.ts b/site/sidebar.ts index b6e95a2ef6..49bbc32d67 100644 --- a/site/sidebar.ts +++ b/site/sidebar.ts @@ -1116,8 +1116,8 @@ export const sidebar = { text: 'Actions', items: [ { - text: 'issuePermissions', - link: '/experimental/erc7715/issuePermissions', + text: 'grantPermissions', + link: '/experimental/erc7715/grantPermissions', }, ], }, diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index d5160134dd..fb1ab4f202 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -1,5 +1,25 @@ # viem +## 2.16.3 + +### Patch Changes + +- [#2436](https://github.com/wevm/viem/pull/2436) [`2357376f`](https://github.com/wevm/viem/commit/2357376fa5c69c28a032bda95cf2f87bb3dac65f) Thanks [@RedHorse823](https://github.com/RedHorse823)! - Added Morph Holeksy Testnet chain. + +- [#2439](https://github.com/wevm/viem/pull/2439) [`76f514c5`](https://github.com/wevm/viem/commit/76f514c5856f7bb1bb329f7e7c69521ecd4596d7) Thanks [@mypeaceduck](https://github.com/mypeaceduck)! - Added multicall3 contract to BitTorrent chain. + +- [#2441](https://github.com/wevm/viem/pull/2441) [`a70db740`](https://github.com/wevm/viem/commit/a70db740cff1306824c8d6ba6d220fb51cfd688a) Thanks [@jiggyBu](https://github.com/jiggyBu)! - Added real & unreal chains + +- [#2440](https://github.com/wevm/viem/pull/2440) [`76447337`](https://github.com/wevm/viem/commit/76447337de60f272179b25374a75a422180f45cc) Thanks [@devon-n](https://github.com/devon-n)! - Added Etherlink Mainnet chain + +## 2.16.2 + +### Patch Changes + +- [#2354](https://github.com/wevm/viem/pull/2354) [`b8fc0dc`](https://github.com/wevm/viem/commit/b8fc0dc1369a39d871dca9adf6d0c9038275d3cb) Thanks [@oleksiivinogradov](https://github.com/oleksiivinogradov)! - Added dchain chain + +- [`00b353b`](https://github.com/wevm/viem/commit/00b353bf0242de3a18297fcd2eac5e03dcec36be) Thanks [@jxom](https://github.com/jxom)! - **Experimental:** Updated `grantPermissions` to conform to latest spec changes. + ## 2.16.1 ### Patch Changes diff --git a/src/actions/public/mulitcall.bench-d.ts b/src/actions/public/mulitcall.bench-d.ts index 354a2c8ba2..38499faa31 100644 --- a/src/actions/public/mulitcall.bench-d.ts +++ b/src/actions/public/mulitcall.bench-d.ts @@ -1,16 +1,18 @@ -import { bench } from '@arktype/attest' +import { attest } from '@arktype/attest' +import { test } from 'vitest' import { baycContractConfig, usdcContractConfig, } from '../../../test/src/abis.js' -import { anvil } from '../../chains/index.js' +import { mainnet } from '../../chains/index.js' import { createClient } from '../../clients/createClient.js' import { http } from '../../clients/transports/http.js' import { multicall } from './multicall.js' -bench('multicall return type', async () => { - const client = createClient({ chain: anvil, transport: http() }) +const client = createClient({ chain: mainnet, transport: http() }) + +test('return type', () => { const res = multicall(client, { allowFailure: false, contracts: [ @@ -21,7 +23,7 @@ bench('multicall return type', async () => { { ...usdcContractConfig, functionName: 'balanceOf', - args: ['0x...'], + args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'], }, { ...baycContractConfig, @@ -29,5 +31,6 @@ bench('multicall return type', async () => { }, ], }) - return {} as typeof res -}).types([192503, 'instantiations']) + attest.instantiations([80523, 'instantiations']) + attest>(res) +}) diff --git a/src/actions/public/readContract.bench-d.ts b/src/actions/public/readContract.bench-d.ts index ce0b6c2a06..8d41e3fd7d 100644 --- a/src/actions/public/readContract.bench-d.ts +++ b/src/actions/public/readContract.bench-d.ts @@ -1,17 +1,20 @@ -import { bench } from '@arktype/attest' +import { attest } from '@arktype/attest' +import { test } from 'vitest' import { usdcContractConfig } from '../../../test/src/abis.js' -import { anvil } from '../../chains/index.js' +import { mainnet } from '../../chains/index.js' import { createClient } from '../../clients/createClient.js' import { http } from '../../clients/transports/http.js' import { readContract } from './readContract.js' -bench('readContract return type', async () => { - const client = createClient({ chain: anvil, transport: http() }) +const client = createClient({ chain: mainnet, transport: http() }) + +test('return type', () => { const res = readContract(client, { ...usdcContractConfig, functionName: 'balanceOf', - args: ['0x...'], + args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'], }) - return {} as typeof res -}).types([152288, 'instantiations']) + attest.instantiations([39383, 'instantiations']) + attest>(res) +}) diff --git a/src/chains/definitions/bitTorrent.ts b/src/chains/definitions/bitTorrent.ts index c582d9d4d4..a71a64c353 100644 --- a/src/chains/definitions/bitTorrent.ts +++ b/src/chains/definitions/bitTorrent.ts @@ -16,4 +16,10 @@ export const bitTorrent = /*#__PURE__*/ defineChain({ apiUrl: 'https://api.bttcscan.com/api', }, }, + contracts: { + multicall3: { + address: '0xcA11bde05977b3631167028862bE2a173976CA11', + blockCreated: 31078552, + }, + }, }) diff --git a/src/chains/definitions/dchain.ts b/src/chains/definitions/dchain.ts new file mode 100644 index 0000000000..c08748fa65 --- /dev/null +++ b/src/chains/definitions/dchain.ts @@ -0,0 +1,24 @@ +import { chainConfig } from '../../op-stack/chainConfig.js' +import { defineChain } from '../../utils/chain/defineChain.js' + +export const dchain = /*#__PURE__*/ defineChain({ + ...chainConfig, + id: 2716446429837000, + name: 'Dchain', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: ['https://dchain-2716446429837000-1.jsonrpc.sagarpc.io'], + }, + }, + blockExplorers: { + default: { + name: 'Dchain Explorer', + url: 'https://dchain-2716446429837000-1.sagaexplorer.io', + apiUrl: 'https://api-dchain-2716446429837000-1.sagaexplorer.io/api', + }, + }, + contracts: { + ...chainConfig.contracts, + }, +}) diff --git a/src/chains/definitions/dchainTestnet.ts b/src/chains/definitions/dchainTestnet.ts new file mode 100644 index 0000000000..8f451db405 --- /dev/null +++ b/src/chains/definitions/dchainTestnet.ts @@ -0,0 +1,27 @@ +import { chainConfig } from '../../op-stack/chainConfig.js' +import { defineChain } from '../../utils/chain/defineChain.js' + +export const dchainTestnet = /*#__PURE__*/ defineChain({ + ...chainConfig, + id: 2713017997578000, + name: 'Dchain Testnet', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: [ + 'https://dchaintestnet-2713017997578000-1.jsonrpc.testnet.sagarpc.io', + ], + }, + }, + blockExplorers: { + default: { + name: 'Dchain Explorer', + url: 'https://dchaintestnet-2713017997578000-1.testnet.sagaexplorer.io', + apiUrl: + 'https://api-dchaintestnet-2713017997578000-1.testnet.sagaexplorer.io/api', + }, + }, + contracts: { + ...chainConfig.contracts, + }, +}) diff --git a/src/chains/definitions/etherlink.ts b/src/chains/definitions/etherlink.ts new file mode 100644 index 0000000000..5b4c4dfaa4 --- /dev/null +++ b/src/chains/definitions/etherlink.ts @@ -0,0 +1,26 @@ +import { defineChain } from '../../utils/chain/defineChain.js' + +export const etherlink = /*#__PURE__*/ defineChain({ + id: 42793, + name: 'Etherlink', + nativeCurrency: { + decimals: 18, + name: 'Tez', + symbol: 'XTZ', + }, + rpcUrls: { + default: { http: ['https://node.mainnet.etherlink.com'] }, + }, + blockExplorers: { + default: { + name: 'Etherlink', + url: 'https://explorer.etherlink.com', + }, + }, + contracts: { + multicall3: { + address: '0xcA11bde05977b3631167028862bE2a173976CA11', + blockCreated: 33899, + }, + }, +}) diff --git a/src/chains/definitions/morphHolesky.ts b/src/chains/definitions/morphHolesky.ts new file mode 100644 index 0000000000..5254672ac9 --- /dev/null +++ b/src/chains/definitions/morphHolesky.ts @@ -0,0 +1,21 @@ +import { defineChain } from '../../utils/chain/defineChain.js' + +export const morphHolesky = /*#__PURE__*/ defineChain({ + id: 2810, + name: 'Morph Holesky', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + rpcUrls: { + default: { + http: ['https://rpc-quicknode-holesky.morphl2.io'], + webSocket: ['wss://rpc-quicknode-holesky.morphl2.io'], + }, + }, + blockExplorers: { + default: { + name: 'Morph Holesky Explorer', + url: 'https://explorer-holesky.morphl2.io', + apiUrl: 'https://explorer-api-holesky.morphl2.io/api?', + }, + }, + testnet: true, +}) diff --git a/src/chains/definitions/real.ts b/src/chains/definitions/real.ts new file mode 100644 index 0000000000..cf60eda4bc --- /dev/null +++ b/src/chains/definitions/real.ts @@ -0,0 +1,27 @@ +import { defineChain } from '../../utils/chain/defineChain.js' + +export const real = /*#__PURE__*/ defineChain({ + id: 111188, + name: 're.al', + nativeCurrency: { + name: 'reETH', + decimals: 18, + symbol: 'reETH', + }, + rpcUrls: { + default: { http: ['https://real.drpc.org'] }, + }, + blockExplorers: { + default: { + name: 're.al Explorer', + url: 'https://explorer.re.al', + apiUrl: 'https://explorer.re.al/api/v2', + }, + }, + contracts: { + multicall3: { + address: '0xcA11bde05977b3631167028862bE2a173976CA11', + blockCreated: 695, + }, + }, +}) diff --git a/src/chains/definitions/unreal.ts b/src/chains/definitions/unreal.ts new file mode 100644 index 0000000000..4e2cc4299b --- /dev/null +++ b/src/chains/definitions/unreal.ts @@ -0,0 +1,28 @@ +import { defineChain } from '../../utils/chain/defineChain.js' + +export const unreal = /*#__PURE__*/ defineChain({ + id: 18233, + name: 'Unreal', + nativeCurrency: { + name: 'reETH', + decimals: 18, + symbol: 'reETH', + }, + rpcUrls: { + default: { http: ['https://rpc.unreal-orbit.gelato.digital'] }, + }, + blockExplorers: { + default: { + name: 'Unreal Explorer', + url: 'https://unreal.blockscout.com', + apiUrl: 'https://unreal.blockscout.com/api/v2', + }, + }, + testnet: true, + contracts: { + multicall3: { + address: '0x8b6B0e60D8CD84898Ea8b981065A12F876eA5677', + blockCreated: 1745, + }, + }, +}) diff --git a/src/chains/index.ts b/src/chains/index.ts index eca2b72951..e6ade6e5fc 100644 --- a/src/chains/index.ts +++ b/src/chains/index.ts @@ -62,6 +62,8 @@ export { crossbell } from './definitions/crossbell.js' export { cyber } from './definitions/cyber.js' export { cyberTestnet } from './definitions/cyberTestnet.js' export { darwinia } from './definitions/darwinia.js' +export { dchain } from './definitions/dchain.js' +export { dchainTestnet } from './definitions/dchainTestnet.js' export { defichainEvm } from './definitions/defichainEvm.js' export { defichainEvmTestnet } from './definitions/defichainEvmTestnet.js' export { degen } from './definitions/degen.js' @@ -76,6 +78,7 @@ export { edgewareTestnet } from './definitions/edgewareTestnet.js' export { eon } from './definitions/eon.js' export { eos } from './definitions/eos.js' export { eosTestnet } from './definitions/eosTestnet.js' +export { etherlink } from './definitions/etherlink.js' export { etherlinkTestnet } from './definitions/etherlinkTestnet.js' export { evmos } from './definitions/evmos.js' export { evmosTestnet } from './definitions/evmosTestnet.js' @@ -169,6 +172,7 @@ export { moonbaseAlpha } from './definitions/moonbaseAlpha.js' export { moonbeam } from './definitions/moonbeam.js' export { moonbeamDev } from './definitions/moonbeamDev.js' export { moonriver } from './definitions/moonriver.js' +export { morphHolesky } from './definitions/morphHolesky.js' export { morphSepolia } from './definitions/morphSepolia.js' export { nautilus } from './definitions/nautilus.js' export { neonDevnet } from './definitions/neonDevnet.js' @@ -204,6 +208,7 @@ export { pulsechain } from './definitions/pulsechain.js' export { pulsechainV4 } from './definitions/pulsechainV4.js' export { qMainnet } from './definitions/qMainnet.js' export { qTestnet } from './definitions/qTestnet.js' +export { real } from './definitions/real.js' export { redbellyTestnet } from './definitions/redbellyTestnet.js' export { redstone } from './definitions/redstone.js' export { reyaNetwork } from './definitions/reyaNetwork.js' @@ -261,6 +266,7 @@ export { telosTestnet } from './definitions/telosTestnet.js' export { tenet } from './definitions/tenet.js' export { thaiChain } from './definitions/thaiChain.js' export { thunderTestnet } from './definitions/thunderTestnet.js' +export { unreal } from './definitions/unreal.js' export { vechain } from './definitions/vechain.js' export { wanchain } from './definitions/wanchain.js' export { wanchainTestnet } from './definitions/wanchainTestnet.js' diff --git a/src/clients/createPublicClient.bench-d.ts b/src/clients/createPublicClient.bench-d.ts index 160b159d80..bc6dfab781 100644 --- a/src/clients/createPublicClient.bench-d.ts +++ b/src/clients/createPublicClient.bench-d.ts @@ -1,16 +1,21 @@ -import { bench } from '@arktype/attest' +import { attest } from '@arktype/attest' +import { test } from 'vitest' import { createClient } from './createClient.js' import { createPublicClient } from './createPublicClient.js' import { publicActions } from './decorators/public.js' import { http } from './transports/http.js' -bench('createPublicClient', () => { - const client = createPublicClient({ transport: http() }) - return {} as typeof client -}).types([13470, 'instantiations']) +test('createPublicClient', () => { + createPublicClient({ + transport: http('https://cloudflare-eth.com'), + }) + attest.instantiations([12236, 'instantiations']) +}) -bench('createClient.extend + publicActions', () => { - const client = createClient({ transport: http() }).extend(publicActions) - return {} as typeof client -}).types([246356, 'instantiations']) +test('createClient.extend + publicActions', () => { + createClient({ + transport: http('https://cloudflare-eth.com'), + }).extend(publicActions) + attest.instantiations([247705, 'instantiations']) +}) diff --git a/src/clients/createTestClient.bench-d.ts b/src/clients/createTestClient.bench-d.ts index dfb1d7e2ed..c777ce5269 100644 --- a/src/clients/createTestClient.bench-d.ts +++ b/src/clients/createTestClient.bench-d.ts @@ -1,18 +1,22 @@ -import { bench } from '@arktype/attest' +import { attest } from '@arktype/attest' +import { test } from 'vitest' import { createClient } from './createClient.js' import { createTestClient } from './createTestClient.js' import { testActions } from './decorators/test.js' import { http } from './transports/http.js' -bench('createTestClient', () => { - const client = createTestClient({ mode: 'anvil', transport: http() }) - return {} as typeof client -}).types([668, 'instantiations']) +test('createTestClient', () => { + createTestClient({ + mode: 'anvil', + transport: http('https://cloudflare-eth.com'), + }) + attest.instantiations([690, 'instantiations']) +}) -bench('createClient.extend + testActions', () => { - const client = createClient({ transport: http() }).extend( - testActions({ mode: 'anvil' }), - ) - return {} as typeof client -}).types([6275, 'instantiations']) +test('createClient.extend + testActions', () => { + createClient({ + transport: http('https://cloudflare-eth.com'), + }).extend(testActions({ mode: 'anvil' })) + attest.instantiations([6329, 'instantiations']) +}) diff --git a/src/clients/createWalletClient.bench-d.ts b/src/clients/createWalletClient.bench-d.ts index 6cfe9e18e1..893e2f9336 100644 --- a/src/clients/createWalletClient.bench-d.ts +++ b/src/clients/createWalletClient.bench-d.ts @@ -1,16 +1,21 @@ -import { bench } from '@arktype/attest' +import { attest } from '@arktype/attest' +import { test } from 'vitest' import { createClient } from './createClient.js' import { createWalletClient } from './createWalletClient.js' import { walletActions } from './decorators/wallet.js' import { http } from './transports/http.js' -bench('createWalletClient', () => { - const client = createWalletClient({ transport: http() }) - return {} as typeof client -}).types([1384, 'instantiations']) +test('createWalletClient', () => { + createWalletClient({ + transport: http('https://cloudflare-eth.com'), + }) + attest.instantiations([1408, 'instantiations']) +}) -bench('createClient.extend + walletActions', () => { - const client = createClient({ transport: http() }).extend(walletActions) - return {} as typeof client -}).types([193153, 'instantiations']) +test('createClient.extend + walletActions', () => { + createClient({ + transport: http('https://cloudflare-eth.com'), + }).extend(walletActions) + attest.instantiations([179759, 'instantiations']) +}) diff --git a/src/errors/version.ts b/src/errors/version.ts index 27116e0880..b49a66c41d 100644 --- a/src/errors/version.ts +++ b/src/errors/version.ts @@ -1 +1 @@ -export const version = '2.16.1' +export const version = '2.16.3' diff --git a/src/experimental/erc7715/actions/grantPermissions.test.ts b/src/experimental/erc7715/actions/grantPermissions.test.ts new file mode 100644 index 0000000000..7e7e953dd9 --- /dev/null +++ b/src/experimental/erc7715/actions/grantPermissions.test.ts @@ -0,0 +1,636 @@ +import { expect, test } from 'vitest' +import { accounts } from '../../../../test/src/constants.js' +import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' +import { createClient } from '../../../clients/createClient.js' +import { custom } from '../../../clients/transports/custom.js' +import { parseEther } from '../../../utils/index.js' +import { grantPermissions } from './grantPermissions.js' + +const getClient = ({ onRequest }: { onRequest: (params: any) => void }) => + createClient({ + transport: custom({ + async request({ method, params }) { + onRequest(params) + if (method === 'wallet_grantPermissions') + return { + grantedPermissions: params[0].permissions, + expiry: params[0].expiry, + permissionsContext: '0xdeadbeef', + } + return null + }, + }), + }) + +test('default', async () => { + const requests: any[] = [] + const client = getClient({ + onRequest(request) { + requests.push(request) + }, + }) + + expect( + await grantPermissions(client, { + expiry: 1716846083638, + permissions: [ + { + type: 'native-token-transfer', + data: { + ticker: 'ETH', + }, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + { + type: 'rate-limit', + data: { + count: 69, + interval: 1, + }, + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + }, + ], + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + policies: [ + { + type: 'gas-limit', + data: { + limit: parseEther('1'), + }, + }, + ], + }, + ], + }), + ).toMatchInlineSnapshot(` + { + "expiry": 1716846083638, + "grantedPermissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": 1000000000000000000n, + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [ + { + "data": { + "limit": 1000000000000000000n, + }, + "type": "gas-limit", + }, + ], + "required": false, + "type": "foo", + }, + ], + "permissionsContext": "0xdeadbeef", + } + `) + expect(requests).toMatchInlineSnapshot(` + [ + [ + { + "expiry": 1716846083638, + "permissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": "0xde0b6b3a7640000", + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [ + { + "data": { + "limit": "0xde0b6b3a7640000", + }, + "type": "gas-limit", + }, + ], + "required": false, + "type": "foo", + }, + ], + }, + ], + ] + `) +}) + +test('args: account (local)', async () => { + const requests: any[] = [] + const client = getClient({ + onRequest(request) { + requests.push(request) + }, + }) + + expect( + await grantPermissions(client, { + account: privateKeyToAccount(accounts[0].privateKey), + expiry: 1716846083638, + permissions: [ + { + type: 'native-token-transfer', + data: { + ticker: 'ETH', + }, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + { + type: 'rate-limit', + data: { + count: 69, + interval: 1, + }, + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + }, + ], + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + policies: [], + }, + ], + }), + ).toMatchInlineSnapshot(` + { + "expiry": 1716846083638, + "grantedPermissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": 1000000000000000000n, + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [], + "required": false, + "type": "foo", + }, + ], + "permissionsContext": "0xdeadbeef", + } + `) + expect(requests).toMatchInlineSnapshot(` + [ + [ + { + "expiry": 1716846083638, + "permissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": "0xde0b6b3a7640000", + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [], + "required": false, + "type": "foo", + }, + ], + "signer": { + "data": { + "id": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + }, + "type": "account", + }, + }, + ], + ] + `) +}) + +test('args: account (json-rpc)', async () => { + const requests: any[] = [] + const client = getClient({ + onRequest(request) { + requests.push(request) + }, + }) + + expect( + await grantPermissions(client, { + account: accounts[0].address, + expiry: 1716846083638, + permissions: [ + { + type: 'native-token-transfer', + data: { + ticker: 'ETH', + }, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + { + type: 'rate-limit', + data: { + count: 69, + interval: 1, + }, + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + }, + ], + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + policies: [], + }, + ], + }), + ).toMatchInlineSnapshot(` + { + "expiry": 1716846083638, + "grantedPermissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": 1000000000000000000n, + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [], + "required": false, + "type": "foo", + }, + ], + "permissionsContext": "0xdeadbeef", + } + `) + expect(requests).toMatchInlineSnapshot(` + [ + [ + { + "expiry": 1716846083638, + "permissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": "0xde0b6b3a7640000", + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [], + "required": false, + "type": "foo", + }, + ], + "signer": { + "type": "wallet", + }, + }, + ], + ] + `) +}) + +test('args: signer', async () => { + const requests: any[] = [] + const client = getClient({ + onRequest(request) { + requests.push(request) + }, + }) + + expect( + await grantPermissions(client, { + expiry: 1716846083638, + signer: { + type: 'key', + data: { + id: '0x123', + }, + }, + permissions: [ + { + type: 'native-token-transfer', + data: { + ticker: 'ETH', + }, + policies: [ + { + type: 'token-allowance', + data: { + allowance: parseEther('1'), + }, + }, + { + type: 'rate-limit', + data: { + count: 69, + interval: 1, + }, + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + }, + ], + }, + { + type: { custom: 'foo' }, + data: { bar: 'baz' }, + policies: [ + { + type: 'gas-limit', + data: { + limit: parseEther('1'), + }, + }, + ], + }, + ], + }), + ).toMatchInlineSnapshot(` + { + "expiry": 1716846083638, + "grantedPermissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": 1000000000000000000n, + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [ + { + "data": { + "limit": 1000000000000000000n, + }, + "type": "gas-limit", + }, + ], + "required": false, + "type": "foo", + }, + ], + "permissionsContext": "0xdeadbeef", + } + `) + expect(requests).toMatchInlineSnapshot(` + [ + [ + { + "expiry": 1716846083638, + "permissions": [ + { + "data": { + "ticker": "ETH", + }, + "policies": [ + { + "data": { + "allowance": "0xde0b6b3a7640000", + }, + "type": "token-allowance", + }, + { + "data": { + "count": 69, + "interval": 1, + }, + "type": "rate-limit", + }, + { + "data": { + "bar": "baz", + }, + "type": "foo", + }, + ], + "required": false, + "type": "native-token-transfer", + }, + { + "data": { + "bar": "baz", + }, + "policies": [ + { + "data": { + "limit": "0xde0b6b3a7640000", + }, + "type": "gas-limit", + }, + ], + "required": false, + "type": "foo", + }, + ], + "signer": { + "data": { + "id": "0x123", + }, + "type": "key", + }, + }, + ], + ] + `) +}) diff --git a/src/experimental/erc7715/actions/issuePermissions.ts b/src/experimental/erc7715/actions/grantPermissions.ts similarity index 51% rename from src/experimental/erc7715/actions/issuePermissions.ts rename to src/experimental/erc7715/actions/grantPermissions.ts index e638c8c799..a5bfec5f0e 100644 --- a/src/experimental/erc7715/actions/issuePermissions.ts +++ b/src/experimental/erc7715/actions/grantPermissions.ts @@ -2,14 +2,14 @@ import type { Address } from 'abitype' import type { Client } from '../../../clients/createClient.js' import type { Transport } from '../../../clients/transports/createTransport.js' import type { Account } from '../../../types/account.js' -import type { WalletIssuePermissionsReturnType } from '../../../types/eip1193.js' +import type { WalletGrantPermissionsReturnType } from '../../../types/eip1193.js' import type { Hex } from '../../../types/misc.js' import type { OneOf } from '../../../types/utils.js' -import { numberToHex } from '../../../utils/encoding/toHex.js' +import { numberToHex, parseAccount } from '../../../utils/index.js' import type { Permission } from '../types/permission.js' import type { Signer } from '../types/signer.js' -export type IssuePermissionsParameters = { +export type GrantPermissionsParameters = { /** Timestamp (in seconds) that specifies the time by which this session MUST expire. */ expiry: number /** Set of permissions to grant to the user. */ @@ -25,7 +25,7 @@ export type IssuePermissionsParameters = { } > -export type IssuePermissionsReturnType = { +export type GrantPermissionsReturnType = { /** Timestamp (in seconds) that specifies the time by which this session MUST expire. */ expiry: number /** ERC-4337 Factory to deploy smart contract account. */ @@ -33,7 +33,7 @@ export type IssuePermissionsReturnType = { /** Calldata to use when calling the ERC-4337 Factory. */ factoryData?: string | undefined /** Set of granted permissions. */ - grantedPermissions: Omit[] + grantedPermissions: readonly Permission[] /** Permissions identifier. */ permissionsContext: string /** Signer attached to the permissions. */ @@ -48,76 +48,80 @@ export type IssuePermissionsReturnType = { /** * Request permissions from a wallet to perform actions on behalf of a user. * - * - Docs: https://viem.sh/experimental/erc7715/issuePermissions + * - Docs: https://viem.sh/experimental/erc7715/grantPermissions * * @example * import { createWalletClient, custom } from 'viem' * import { mainnet } from 'viem/chains' - * import { issuePermissions } from 'viem/experimental' + * import { grantPermissions } from 'viem/experimental' * * const client = createWalletClient({ * chain: mainnet, * transport: custom(window.ethereum), * }) * - * const result = await issuePermissions(client, { + * const result = await grantPermissions(client, { * expiry: 1716846083638, * permissions: [ * { - * type: 'contract-call', + * type: 'native-token-transfer', * data: { - * address: '0x0000000000000000000000000000000000000000', - * }, - * }, - * { - * type: 'native-token-limit', - * data: { - * amount: 69420n, + * ticker: 'ETH', * }, + * policies: [ + * { + * type: 'token-allowance', + * data: { + * allowance: parseEther('1'), + * }, + * } + * ], * required: true, * }, * ], * }) */ -export async function issuePermissions( +export async function grantPermissions( client: Client, - parameters: IssuePermissionsParameters, -): Promise { - const { expiry, permissions, signer } = parameters + parameters: GrantPermissionsParameters, +): Promise { + const { account, expiry, permissions, signer } = parameters const result = await client.request( { - method: 'wallet_issuePermissions', - params: [parseParameters({ expiry, permissions, signer })], + method: 'wallet_grantPermissions', + params: [ + formatParameters({ account, expiry, permissions, signer } as any), + ], }, { retryCount: 0 }, ) - return parseResult(result) as IssuePermissionsReturnType + return formatRequest(result) as GrantPermissionsReturnType } -function parseParameters(parameters: IssuePermissionsParameters) { - const { account, expiry, permissions, signer: signer_ } = parameters +function formatParameters(parameters: GrantPermissionsParameters) { + const { expiry, permissions, signer: signer_ } = parameters + + const account = parameters.account + ? parseAccount(parameters.account) + : undefined const signer = (() => { if (!account && !signer_) return undefined - if (account) { - // Address as signer. - if (typeof account === 'string') - return { - type: 'account', - data: { - id: account, - }, - } + // JSON-RPC Account as signer. + if (account?.type === 'json-rpc') + return { + type: 'wallet', + } - // Viem Account as signer. + // Local Account as signer. + if (account?.type === 'local') return { type: 'account', data: { id: account.address, }, } - } // ERC-7715 Signer as signer. return signer_ @@ -127,36 +131,60 @@ function parseParameters(parameters: IssuePermissionsParameters) { expiry, permissions: permissions.map((permission) => ({ ...permission, - ...(permission.data && typeof permission.data === 'object' - ? { - data: { - ...permission.data, - ...('amount' in permission.data && - typeof permission.data.amount === 'bigint' - ? { amount: numberToHex(permission.data.amount) } - : {}), - }, - } - : {}), + policies: permission.policies.map((policy) => { + const data = (() => { + if (policy.type === 'token-allowance') + return { + allowance: numberToHex(policy.data.allowance), + } + if (policy.type === 'gas-limit') + return { + limit: numberToHex(policy.data.limit), + } + return policy.data + })() + + return { + data, + type: + typeof policy.type === 'string' ? policy.type : policy.type.custom, + } + }), required: permission.required ?? false, + type: + typeof permission.type === 'string' + ? permission.type + : permission.type.custom, })), ...(signer ? { signer } : {}), } } -function parseResult(result: WalletIssuePermissionsReturnType) { +function formatRequest(result: WalletGrantPermissionsReturnType) { return { expiry: result.expiry, ...(result.factory ? { factory: result.factory } : {}), ...(result.factoryData ? { factoryData: result.factoryData } : {}), grantedPermissions: result.grantedPermissions.map((permission) => ({ ...permission, - data: { - ...permission.data, - ...('amount' in permission.data - ? { amount: BigInt(permission.data.amount) } - : {}), - }, + policies: permission.policies.map((policy) => { + const data = (() => { + if (policy.type === 'token-allowance') + return { + allowance: BigInt((policy.data as any).allowance), + } + if (policy.type === 'gas-limit') + return { + limit: BigInt((policy.data as any).limit), + } + return policy.data + })() + + return { + data, + type: policy.type, + } + }), })), permissionsContext: result.permissionsContext, ...(result.signerData ? { signerData: result.signerData } : {}), diff --git a/src/experimental/erc7715/actions/issuePermissions.test.ts b/src/experimental/erc7715/actions/issuePermissions.test.ts deleted file mode 100644 index f954ac64b2..0000000000 --- a/src/experimental/erc7715/actions/issuePermissions.test.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { expect, test } from 'vitest' -import { accounts } from '../../../../test/src/constants.js' -import { privateKeyToAccount } from '../../../accounts/privateKeyToAccount.js' -import { createClient } from '../../../clients/createClient.js' -import { custom } from '../../../clients/transports/custom.js' -import { issuePermissions } from './issuePermissions.js' - -const getClient = ({ onRequest }: { onRequest: (params: any) => void }) => - createClient({ - transport: custom({ - async request({ method, params }) { - onRequest(params) - if (method === 'wallet_issuePermissions') - return { - grantedPermissions: params[0].permissions.map( - (permission: any) => ({ - type: permission.type, - data: permission.data, - }), - ), - expiry: params[0].expiry, - permissionsContext: '0xdeadbeef', - } - return null - }, - }), - }) - -test('default', async () => { - const requests: any[] = [] - const client = getClient({ - onRequest(request) { - requests.push(request) - }, - }) - - expect( - await issuePermissions(client, { - expiry: 1716846083638, - signer: { - type: 'account', - data: { - id: '0x0000000000000000000000000000000000000000', - }, - }, - permissions: [ - { - type: 'contract-call', - data: { - address: '0x0000000000000000000000000000000000000000', - }, - }, - { - type: 'native-token-limit', - data: { - amount: 69420n, - }, - required: true, - }, - ], - }), - ).toMatchInlineSnapshot(` - { - "expiry": 1716846083638, - "grantedPermissions": [ - { - "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "type": "contract-call", - }, - { - "data": { - "amount": 69420n, - }, - "type": "native-token-limit", - }, - ], - "permissionsContext": "0xdeadbeef", - } - `) - expect(requests).toMatchInlineSnapshot(` - [ - [ - { - "expiry": 1716846083638, - "permissions": [ - { - "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "required": false, - "type": "contract-call", - }, - { - "data": { - "amount": "0x10f2c", - }, - "required": true, - "type": "native-token-limit", - }, - ], - "signer": { - "data": { - "id": "0x0000000000000000000000000000000000000000", - }, - "type": "account", - }, - }, - ], - ] - `) -}) - -test('args: account as signer', async () => { - const requests: any[] = [] - const client = getClient({ - onRequest(request) { - requests.push(request) - }, - }) - - expect( - await issuePermissions(client, { - account: privateKeyToAccount(accounts[0].privateKey), - expiry: 1716846083638, - permissions: [ - { - type: 'contract-call', - data: { - address: '0x0000000000000000000000000000000000000000', - }, - }, - { - type: 'native-token-limit', - data: { - amount: 69420n, - }, - required: true, - }, - ], - }), - ).toMatchInlineSnapshot(` - { - "expiry": 1716846083638, - "grantedPermissions": [ - { - "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "type": "contract-call", - }, - { - "data": { - "amount": 69420n, - }, - "type": "native-token-limit", - }, - ], - "permissionsContext": "0xdeadbeef", - } - `) - expect(requests).toMatchInlineSnapshot(` - [ - [ - { - "expiry": 1716846083638, - "permissions": [ - { - "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "required": false, - "type": "contract-call", - }, - { - "data": { - "amount": "0x10f2c", - }, - "required": true, - "type": "native-token-limit", - }, - ], - }, - ], - ] - `) -}) - -test('args: address as signer', async () => { - const requests: any[] = [] - const client = getClient({ - onRequest(request) { - requests.push(request) - }, - }) - - expect( - await issuePermissions(client, { - account: accounts[0].address, - expiry: 1716846083638, - permissions: [ - { - type: 'contract-call', - data: { - address: '0x0000000000000000000000000000000000000000', - }, - }, - { - type: 'native-token-limit', - data: { - amount: 69420n, - }, - required: true, - }, - ], - }), - ).toMatchInlineSnapshot(` - { - "expiry": 1716846083638, - "grantedPermissions": [ - { - "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "type": "contract-call", - }, - { - "data": { - "amount": 69420n, - }, - "type": "native-token-limit", - }, - ], - "permissionsContext": "0xdeadbeef", - } - `) - expect(requests).toMatchInlineSnapshot(` - [ - [ - { - "expiry": 1716846083638, - "permissions": [ - { - "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "required": false, - "type": "contract-call", - }, - { - "data": { - "amount": "0x10f2c", - }, - "required": true, - "type": "native-token-limit", - }, - ], - }, - ], - ] - `) -}) diff --git a/src/experimental/erc7715/decorators/erc7715.test.ts b/src/experimental/erc7715/decorators/erc7715.test.ts index ebcacd0db2..2c194e6d0c 100644 --- a/src/experimental/erc7715/decorators/erc7715.test.ts +++ b/src/experimental/erc7715/decorators/erc7715.test.ts @@ -7,12 +7,9 @@ import { walletActionsErc7715 } from './erc7715.js' const client = createClient({ transport: custom({ async request({ method, params }) { - if (method === 'wallet_issuePermissions') + if (method === 'wallet_grantPermissions') return { - grantedPermissions: params[0].permissions.map((permission: any) => ({ - type: permission.type, - data: permission.data, - })), + grantedPermissions: params[0].permissions, expiry: params[0].expiry, permissionsContext: '0xdeadbeef', } @@ -25,15 +22,15 @@ const client = createClient({ test('default', async () => { expect(walletActionsErc7715()(client)).toMatchInlineSnapshot(` { - "issuePermissions": [Function], + "grantPermissions": [Function], } `) }) describe('smoke test', () => { - test('issuePermissions', async () => { + test('grantPermissions', async () => { expect( - await client.issuePermissions({ + await client.grantPermissions({ expiry: 1716846083638, signer: { type: 'account', @@ -43,17 +40,18 @@ describe('smoke test', () => { }, permissions: [ { - type: 'contract-call', + type: 'native-token-transfer', data: { - address: '0x0000000000000000000000000000000000000000', + ticker: 'ETH', }, - }, - { - type: 'native-token-limit', - data: { - amount: 69420n, - }, - required: true, + policies: [ + { + type: 'token-allowance', + data: { + allowance: 1n, + }, + }, + ], }, ], }), @@ -63,15 +61,18 @@ describe('smoke test', () => { "grantedPermissions": [ { "data": { - "address": "0x0000000000000000000000000000000000000000", - }, - "type": "contract-call", - }, - { - "data": { - "amount": 69420n, + "ticker": "ETH", }, - "type": "native-token-limit", + "policies": [ + { + "data": { + "allowance": 1n, + }, + "type": "token-allowance", + }, + ], + "required": false, + "type": "native-token-transfer", }, ], "permissionsContext": "0xdeadbeef", diff --git a/src/experimental/erc7715/decorators/erc7715.ts b/src/experimental/erc7715/decorators/erc7715.ts index 830449ea87..3a97688b05 100644 --- a/src/experimental/erc7715/decorators/erc7715.ts +++ b/src/experimental/erc7715/decorators/erc7715.ts @@ -3,16 +3,16 @@ import type { Transport } from '../../../clients/transports/createTransport.js' import type { Account } from '../../../types/account.js' import type { Chain } from '../../../types/chain.js' import { - type IssuePermissionsParameters, - type IssuePermissionsReturnType, - issuePermissions, -} from '../actions/issuePermissions.js' + type GrantPermissionsParameters, + type GrantPermissionsReturnType, + grantPermissions, +} from '../actions/grantPermissions.js' export type WalletActionsErc7715 = { /** * Request permissions from a wallet to perform actions on behalf of a user. * - * - Docs: https://viem.sh/experimental/erc7715/issuePermissions + * - Docs: https://viem.sh/experimental/erc7715/grantPermissions * * @example * import { createWalletClient, custom } from 'viem' @@ -24,7 +24,7 @@ export type WalletActionsErc7715 = { * transport: custom(window.ethereum), * }).extend(walletActionsErc7715()) * - * const result = await client.issuePermissions({ + * const result = await client.grantPermissions({ * expiry: 1716846083638, * permissions: [ * { @@ -43,9 +43,9 @@ export type WalletActionsErc7715 = { * ], * }) */ - issuePermissions: ( - parameters: IssuePermissionsParameters, - ) => Promise + grantPermissions: ( + parameters: GrantPermissionsParameters, + ) => Promise } /** @@ -63,7 +63,7 @@ export type WalletActionsErc7715 = { * transport: http(), * }).extend(walletActionsErc7715()) * - * const result = await walletClient.issuePermissions({...}) + * const result = await walletClient.grantPermissions({...}) */ export function walletActionsErc7715() { return < @@ -74,7 +74,7 @@ export function walletActionsErc7715() { client: Client, ): WalletActionsErc7715 => { return { - issuePermissions: (parameters) => issuePermissions(client, parameters), + grantPermissions: (parameters) => grantPermissions(client, parameters), } } } diff --git a/src/experimental/erc7715/types/permission.ts b/src/experimental/erc7715/types/permission.ts index 9dcc576374..139bdab386 100644 --- a/src/experimental/erc7715/types/permission.ts +++ b/src/experimental/erc7715/types/permission.ts @@ -1,51 +1,53 @@ import type { Address } from 'abitype' import type { OneOf } from '../../../types/utils.js' +import type { Policy } from './policy.js' /** @internal */ -export type NativeTokenLimitPermission = { - type: 'native-token-limit' - data: { - amount: amount - } +export type CustomPermission = { + data: data + type: type } /** @internal */ -export type Erc20LimitPermission = { - type: 'erc20-limit' +export type NativeTokenTransferPermission = { + type: 'native-token-transfer' data: { - erc20Address: Address - amount: amount + /** Native token ticker (e.g. ETH). */ + ticker: string } } /** @internal */ -export type GasLimitPermission = { - type: 'gas-limit' +export type Erc20TokenTransferPermission = { + type: 'erc20-token-transfer' data: { - amount: amount + /** ERC20 address. */ + address: Address + /** Native token ticker (e.g. ETH). */ + ticker: string } } /** @internal */ export type ContractCallPermission = { type: 'contract-call' - data: unknown -} - -/** @internal */ -export type RateLimitPermission = { - type: 'rate-limit' data: { - count: number - interval: number + /** Contract address. */ + address: Address + /** Set of contract signatures to permit. */ + calls: string[] } } -export type Permission = OneOf< - | NativeTokenLimitPermission - | Erc20LimitPermission - | GasLimitPermission +export type Permission = OneOf< + | NativeTokenTransferPermission + | Erc20TokenTransferPermission | ContractCallPermission - | RateLimitPermission -> & { required?: boolean | undefined } + | CustomPermission +> & { + /** Set of policies for the permission. */ + policies: readonly Policy[] + /** Whether or not the wallet must grant the permission. */ + required?: boolean | undefined +} diff --git a/src/experimental/erc7715/types/policy.ts b/src/experimental/erc7715/types/policy.ts new file mode 100644 index 0000000000..77d71a8dde --- /dev/null +++ b/src/experimental/erc7715/types/policy.ts @@ -0,0 +1,43 @@ +import type { OneOf } from '../../../types/utils.js' + +/** @internal */ +export type CustomPolicy = { + data: data + type: { custom: string } +} + +/** @internal */ +export type TokenAllowancePolicy = { + type: 'token-allowance' + data: { + /** Token allowance (in wei). */ + allowance: uint256 + } +} + +/** @internal */ +export type GasLimitPolicy = { + type: 'gas-limit' + data: { + /** Gas limit (in wei). */ + limit: uint256 + } +} + +/** @internal */ +export type RateLimitPolicy = { + type: 'rate-limit' + data: { + /** Number of times during each interval. */ + count: number + /** Interval (in seconds). */ + interval: number + } +} + +export type Policy = OneOf< + | TokenAllowancePolicy + | GasLimitPolicy + | RateLimitPolicy + | CustomPolicy +> diff --git a/src/experimental/erc7715/types/signer.ts b/src/experimental/erc7715/types/signer.ts index 0d3facd646..ee2ef51716 100644 --- a/src/experimental/erc7715/types/signer.ts +++ b/src/experimental/erc7715/types/signer.ts @@ -25,4 +25,11 @@ export type MultiKeySigner = { } } -export type Signer = OneOf +/** @internal */ +export type WalletSigner = { + type: 'wallet' +} + +export type Signer = OneOf< + AccountSigner | KeySigner | MultiKeySigner | WalletSigner +> diff --git a/src/experimental/index.ts b/src/experimental/index.ts index 9da5373bfe..5521da61ae 100644 --- a/src/experimental/index.ts +++ b/src/experimental/index.ts @@ -67,10 +67,10 @@ export { } from '../utils/signature/serializeErc6492Signature.js' export { - type IssuePermissionsParameters, - type IssuePermissionsReturnType, - issuePermissions, -} from './erc7715/actions/issuePermissions.js' + type GrantPermissionsParameters, + type GrantPermissionsReturnType, + grantPermissions, +} from './erc7715/actions/grantPermissions.js' export { type WalletActionsErc7715, walletActionsErc7715, diff --git a/src/index.ts b/src/index.ts index f30f13751f..2f96717c5a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1021,8 +1021,8 @@ export type { WalletCapabilitiesRecord, WalletCallReceipt, WalletGetCallsStatusReturnType, - WalletIssuePermissionsParameters, - WalletIssuePermissionsReturnType, + WalletGrantPermissionsParameters, + WalletGrantPermissionsReturnType, WalletSendCallsParameters, WalletPermissionCaveat, WalletPermission, diff --git a/src/jsr.json b/src/jsr.json index 870e4abb09..f681b440e8 100644 --- a/src/jsr.json +++ b/src/jsr.json @@ -1,6 +1,6 @@ { "name": "@wevm/viem", - "version": "2.16.1", + "version": "2.16.3", "exports": { ".": "./index.ts", "./accounts": "./accounts/index.ts", diff --git a/src/package.json b/src/package.json index 3bdfc6ecc6..5b268bf969 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "viem", "description": "TypeScript Interface for Ethereum", - "version": "2.16.1", + "version": "2.16.3", "type": "module", "main": "./_cjs/index.js", "module": "./_esm/index.js", diff --git a/src/types/eip1193.ts b/src/types/eip1193.ts index e51cd82ce4..c4b1a68ded 100644 --- a/src/types/eip1193.ts +++ b/src/types/eip1193.ts @@ -131,28 +131,37 @@ export type WalletCallReceipt = { transactionHash: Hex } -export type WalletIssuePermissionsParameters = { +export type WalletGrantPermissionsParameters = { signer?: | { type: string - data: unknown + data?: unknown | undefined } | undefined permissions: readonly { - type: string data: unknown - required: boolean + policies: readonly { + data: unknown + type: string + }[] + required?: boolean | undefined + type: string }[] expiry: number } -export type WalletIssuePermissionsReturnType = { +export type WalletGrantPermissionsReturnType = { expiry: number factory?: `0x${string}` | undefined factoryData?: string | undefined grantedPermissions: readonly { + data: unknown + policies: readonly { + data: unknown + type: string + }[] + required?: boolean | undefined type: string - data: any }[] permissionsContext: string signerData?: @@ -1404,13 +1413,13 @@ export type WalletRpcSchema = [ * @description Requests permissions from a wallet * @link https://eips.ethereum.org/EIPS/eip-7715 * @example - * provider.request({ method: 'wallet_issuePermissions', params: [{ ... }] }) + * provider.request({ method: 'wallet_grantPermissions', params: [{ ... }] }) * // => { ... } */ { - Method: 'wallet_issuePermissions' - Parameters?: [WalletIssuePermissionsParameters] - ReturnType: Prettify + Method: 'wallet_grantPermissions' + Parameters?: [WalletGrantPermissionsParameters] + ReturnType: Prettify }, /** * @description Requests the given permissions from the user. diff --git a/test/benchTypesGlobalSetup.ts b/test/benchTypesGlobalSetup.ts new file mode 100644 index 0000000000..6b43566616 --- /dev/null +++ b/test/benchTypesGlobalSetup.ts @@ -0,0 +1,17 @@ +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { setup } from '@arktype/attest' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +export default function () { + return setup({ + benchErrorOnThresholdExceeded: true, + tsconfig: resolve(__dirname, '../tsconfig.json'), + formatter: 'pnpm biome format --write', + }) +} + +// biome-ignore lint/performance/noBarrelFile: +export { teardown } from '@arktype/attest' diff --git a/test/scripts/typebench.ts b/test/scripts/typebench.ts deleted file mode 100644 index 9127a0eb7d..0000000000 --- a/test/scripts/typebench.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { glob } from 'glob' -import { tsImport } from 'tsx/esm/api' - -const paths = await glob('src/**/*.bench-d.ts') -for (const path of paths) { - await tsImport(`../../${path}`, import.meta.url) -} diff --git a/test/vitest.config.ts b/test/vitest.config.ts index 4307e1b706..26947a6e16 100644 --- a/test/vitest.config.ts +++ b/test/vitest.config.ts @@ -20,14 +20,22 @@ export default defineConfig({ '**/_cjs/**', '**/_esm/**', '**/_types/**', + '**/*.bench.ts', + '**/*.bench-d.ts', '**/*.test.ts', + '**/*.test-d.ts', '**/test/**', ], }, environment: 'node', - include: ['src/**/*.test.ts'], - setupFiles: [join(__dirname, './setup.ts')], - globalSetup: [join(__dirname, './globalSetup.ts')], + include: [ + ...(process.env.TYPES ? ['**/*.bench-d.ts'] : []), + 'src/**/*.test.ts', + ], + setupFiles: process.env.TYPES ? [] : [join(__dirname, './setup.ts')], + globalSetup: process.env.TYPES + ? [join(__dirname, './benchTypesGlobalSetup.ts')] + : [join(__dirname, './globalSetup.ts')], hookTimeout: 60_000, testTimeout: 60_000, },