diff --git a/404.html b/404.html index 9fbadfa..bbb26a1 100644 --- a/404.html +++ b/404.html @@ -5,8 +5,8 @@ Page Not Found | Solide - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

Solide
Made with ❤️ by Solide Project
diff --git a/assets/js/12b59fe5.3ed3b1d5.js b/assets/js/12b59fe5.3ed3b1d5.js deleted file mode 100644 index ad3e670..0000000 --- a/assets/js/12b59fe5.3ed3b1d5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8470],{4829:o=>{o.exports=JSON.parse('[{"label":"erc4337","permalink":"/doc/blog/tags/erc-4337","count":1},{"label":"account-abstraction","permalink":"/doc/blog/tags/account-abstraction","count":1},{"label":"ethereum","permalink":"/doc/blog/tags/ethereum","count":1},{"label":"entry-point","permalink":"/doc/blog/tags/entry-point","count":1},{"label":"open-source","permalink":"/doc/blog/tags/open-source","count":2},{"label":"smart-contract","permalink":"/doc/blog/tags/smart-contract","count":2},{"label":"development-tool","permalink":"/doc/blog/tags/development-tool","count":2}]')}}]); \ No newline at end of file diff --git a/assets/js/12b59fe5.d2af7d78.js b/assets/js/12b59fe5.d2af7d78.js new file mode 100644 index 0000000..e7791fe --- /dev/null +++ b/assets/js/12b59fe5.d2af7d78.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8470],{4829:o=>{o.exports=JSON.parse('[{"label":"open-source","permalink":"/doc/blog/tags/open-source","count":2},{"label":"smart-contract","permalink":"/doc/blog/tags/smart-contract","count":2},{"label":"development-tool","permalink":"/doc/blog/tags/development-tool","count":2},{"label":"erc4337","permalink":"/doc/blog/tags/erc-4337","count":1},{"label":"account-abstraction","permalink":"/doc/blog/tags/account-abstraction","count":1},{"label":"ethereum","permalink":"/doc/blog/tags/ethereum","count":1},{"label":"entry-point","permalink":"/doc/blog/tags/entry-point","count":1}]')}}]); \ No newline at end of file diff --git a/assets/js/14e6b30a.2e0b441e.js b/assets/js/14e6b30a.2e0b441e.js deleted file mode 100644 index 85baf5d..0000000 --- a/assets/js/14e6b30a.2e0b441e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8649],{8775:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>m});var r=o(4848),n=o(8453);const a={slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},s="Coming Soon",c={permalink:"/doc/blog/ethereum/erc4337/paymaster",source:"@site/blog/erc4337/paymaster/index.md",title:"ERC4337 - Paymaster",description:"",date:"2024-02-27T04:29:23.846Z",formattedDate:"February 27, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:0,hasTruncateMarker:!1,authors:[{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,prevItem:{title:"ERC4337 - Decoding Ethereum's EntryPoint",permalink:"/doc/blog/ethereum/erc4337/entrypoint"},nextItem:{title:"Welcome",permalink:"/doc/blog/welcome"}},l={authorsImageUrls:[void 0]},m=[];function i(e){return(0,r.jsx)(r.Fragment,{})}function u(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(i,{...e})}):i()}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>c});var r=o(6540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/14e6b30a.5165bd21.js b/assets/js/14e6b30a.5165bd21.js new file mode 100644 index 0000000..c748b27 --- /dev/null +++ b/assets/js/14e6b30a.5165bd21.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8649],{8775:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>m});var r=o(4848),n=o(8453);const a={slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},s="Coming Soon",c={permalink:"/doc/blog/ethereum/erc4337/paymaster",source:"@site/blog/erc4337/paymaster/index.md",title:"ERC4337 - Paymaster",description:"",date:"2024-03-02T08:47:20.000Z",formattedDate:"March 2, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:0,hasTruncateMarker:!1,authors:[{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,nextItem:{title:"ERC4337 - Decoding Ethereum's EntryPoint",permalink:"/doc/blog/ethereum/erc4337/entrypoint"}},i={authorsImageUrls:[void 0]},m=[];function l(e){return(0,r.jsx)(r.Fragment,{})}function u(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l()}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>c});var r=o(6540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2525e643.e7031291.js b/assets/js/2525e643.999eb9aa.js similarity index 56% rename from assets/js/2525e643.e7031291.js rename to assets/js/2525e643.999eb9aa.js index 5377507..4dfb24a 100644 --- a/assets/js/2525e643.e7031291.js +++ b/assets/js/2525e643.999eb9aa.js @@ -1 +1 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[4269],{958:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>i});var n=o(4848),r=o(8453);const a={slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},s=void 0,c={permalink:"/doc/blog/welcome",source:"@site/blog/2024-02-21/index.md",title:"Welcome",description:"Welcome to Solide",date:"2024-02-21T00:00:00.000Z",formattedDate:"February 21, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:.01,hasTruncateMarker:!1,authors:[{name:"A",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"a"},{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,prevItem:{title:"ERC4337 - Paymaster",permalink:"/doc/blog/ethereum/erc4337/paymaster"}},l={authorsImageUrls:[void 0,void 0]},i=[];function m(e){const t={p:"p",...(0,r.R)(),...e.components};return(0,n.jsx)(t.p,{children:"Welcome to Solide"})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(m,{...e})}):m(e)}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>c});var n=o(6540);const r={},a=n.createContext(r);function s(e){const t=n.useContext(a);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[4269],{958:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>c,metadata:()=>a,toc:()=>i});var n=o(4848),r=o(8453);const c={slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},s=void 0,a={permalink:"/doc/blog/welcome",source:"@site/blog/2024-02-21/index.md",title:"Welcome",description:"Welcome to Solide",date:"2024-02-21T00:00:00.000Z",formattedDate:"February 21, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:.01,hasTruncateMarker:!1,authors:[{name:"A",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"a"},{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,prevItem:{title:"ERC4337 - Decoding Ethereum's EntryPoint",permalink:"/doc/blog/ethereum/erc4337/entrypoint"}},l={authorsImageUrls:[void 0,void 0]},i=[];function u(e){const t={p:"p",...(0,r.R)(),...e.components};return(0,n.jsx)(t.p,{children:"Welcome to Solide"})}function m(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(u,{...e})}):u(e)}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>a});var n=o(6540);const r={},c=n.createContext(r);function s(e){const t=n.useContext(c);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(c.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/61eac78a.c080b26e.js b/assets/js/61eac78a.d79d6722.js similarity index 56% rename from assets/js/61eac78a.c080b26e.js rename to assets/js/61eac78a.d79d6722.js index 0753eb6..6cb4f0d 100644 --- a/assets/js/61eac78a.c080b26e.js +++ b/assets/js/61eac78a.d79d6722.js @@ -1 +1 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[6613],{7138:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>i});var n=o(4848),r=o(8453);const a={slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},s=void 0,c={permalink:"/doc/blog/welcome",source:"@site/blog/2024-02-21/index.md",title:"Welcome",description:"Welcome to Solide",date:"2024-02-21T00:00:00.000Z",formattedDate:"February 21, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:.01,hasTruncateMarker:!1,authors:[{name:"A",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"a"},{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,prevItem:{title:"ERC4337 - Paymaster",permalink:"/doc/blog/ethereum/erc4337/paymaster"}},l={authorsImageUrls:[void 0,void 0]},i=[];function m(e){const t={p:"p",...(0,r.R)(),...e.components};return(0,n.jsx)(t.p,{children:"Welcome to Solide"})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(m,{...e})}):m(e)}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>c});var n=o(6540);const r={},a=n.createContext(r);function s(e){const t=n.useContext(a);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[6613],{7138:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>c,metadata:()=>a,toc:()=>i});var n=o(4848),r=o(8453);const c={slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},s=void 0,a={permalink:"/doc/blog/welcome",source:"@site/blog/2024-02-21/index.md",title:"Welcome",description:"Welcome to Solide",date:"2024-02-21T00:00:00.000Z",formattedDate:"February 21, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:.01,hasTruncateMarker:!1,authors:[{name:"A",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"a"},{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"welcome",title:"Welcome",authors:["a","p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,prevItem:{title:"ERC4337 - Decoding Ethereum's EntryPoint",permalink:"/doc/blog/ethereum/erc4337/entrypoint"}},l={authorsImageUrls:[void 0,void 0]},i=[];function u(e){const t={p:"p",...(0,r.R)(),...e.components};return(0,n.jsx)(t.p,{children:"Welcome to Solide"})}function m(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(u,{...e})}):u(e)}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>a});var n=o(6540);const r={},c=n.createContext(r);function s(e){const t=n.useContext(c);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(c.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/74ce7958.4523107a.js b/assets/js/74ce7958.4523107a.js new file mode 100644 index 0000000..4be6e1a --- /dev/null +++ b/assets/js/74ce7958.4523107a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[2905],{5838:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>d,metadata:()=>h,toc:()=>u});var a=n(4848),s=n(8453),i=(n(6540),n(2168)),r=n(3456),o=n(9900),c=n(2345);const d={slug:"/ethereum/erc4337/entrypoint",title:"ERC4337 - Decoding Ethereum's EntryPoint",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["erc4337","account-abstraction","ethereum","entry-point"]},l=void 0,h={permalink:"/doc/blog/ethereum/erc4337/entrypoint",source:"@site/blog/erc4337/entry-point/2024-03-02-index.md",title:"ERC4337 - Decoding Ethereum's EntryPoint",description:"{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"basic",children:"Basic"}),"\n",(0,a.jsxs)(t.p,{children:["Before we go into the details of the EntryPoint, we need to understand the basic flow of how the EntryPoint works. The EntryPoint is a smart contract that is used to execute ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The ",(0,a.jsx)(t.code,{children:"UserOperation"})," is a struct that contains all the necessary information to execute a transaction. The EntryPoint is used to execute multiple UserOperations at once. This is done to save gas costs and to make the execution of transactions more efficient."]}),"\n",(0,a.jsx)(t.h3,{id:"useroperation",children:"UserOperation"}),"\n",(0,a.jsxs)(t.p,{children:["The primary data structure for user interaction within the Account Abstraction framework is encapsulated in ",(0,a.jsx)(t.code,{children:"interfaces/UserOperation.sol"}),". This structure is typically created by the Bundler and transmitted to the EntryPoint contract. The ",(0,a.jsx)(t.code,{children:"UserOperation"})," struct comprises the following fields:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"struct UserOperation {\r\n address sender;\r\n uint256 nonce;\r\n bytes initCode;\r\n bytes callData;\r\n uint256 callGasLimit;\r\n uint256 verificationGasLimit;\r\n uint256 preVerificationGas;\r\n uint256 maxFeePerGas;\r\n uint256 maxPriorityFeePerGas;\r\n bytes paymasterAndData;\r\n bytes signature;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["An example of a ",(0,a.jsx)(t.code,{children:"UserOperation"})," is provided below:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-typescript",children:"const emptyUserOp: UserOperation = {\r\n sender: AddressZero,\r\n callData: '0x',\r\n nonce: 0,\r\n preVerificationGas: 0,\r\n verificationGasLimit: 100000,\r\n callGasLimit: 0,\r\n maxFeePerGas: 0,\r\n maxPriorityFeePerGas: 0,\r\n signature: '0x'\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In contrast to the traditional approach of sending signed transactions to a mempool for validation, the initial step in ERC-4337 involves dispatching an operation in the form of a ",(0,a.jsx)(t.strong,{children:"UserOperation"}),". These operations are then forwarded to an alternative mempool. Users have the capability to dispatch multiple UserOperations concurrently through a Bundler smart contract, referred to as Bundler Transactions."]}),"\n",(0,a.jsx)(t.h3,{id:"entry-point-contract-on-ethereum",children:"Entry Point Contract on Ethereum"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.strong,{children:"EntryPoint"})," (EP) contract on Ethereum, found at ",(0,a.jsx)(t.a,{href:"https://etherscan.io/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",children:"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"}),", is crucial for handling ",(0,a.jsx)(t.code,{children:"bundlerTransactions"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["You can explore this contract using Solidity's IDE ",(0,a.jsx)(t.code,{children:"${SOLIDE_URL}/1/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789)"})]}),"\n",(0,a.jsxs)(t.p,{children:["As of writing this, its contract version is ",(0,a.jsx)(t.code,{children:"0.6.0"})," and serves as the main hub for processing batches of ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The contract offers two main methods: ",(0,a.jsx)(t.code,{children:"handleOps"})," and ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"}),". We'll focus on ",(0,a.jsx)(t.code,{children:"handleOps"})," for now, leaving ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"})," for later discussion."]}),"\n",(0,a.jsxs)(t.h2,{id:"point_right-handleops",children:["\ud83d\udc49"," handleOps"]}),"\n",(0,a.jsxs)(t.p,{children:["The main flow of using the EntryPoint typically comes from the ",(0,a.jsx)(t.code,{children:"Bundler"})," contracts which are called the ",(0,a.jsx)(t.code,{children:"handleOps()"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function handleOps(UserOperation[] calldata ops, address payable beneficiary) public nonReentrant\n"})}),"\n",(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Non-Reentrant Modifier"}),": This modifier prevents reentrancy attacks, ensuring the security of the smart contract."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"UserOperation Array"}),": The ",(0,a.jsx)(t.code,{children:"ops"})," array consists of ",(0,a.jsx)(t.code,{children:"UserOperation"})," objects, stored in ",(0,a.jsx)(t.code,{children:"calldata"}),". These objects hold data passed to the contract's entry point."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Beneficiary Address"}),": The ",(0,a.jsx)(t.code,{children:"beneficiary"})," address is where gas refunds are sent after execution. Typically, this address corresponds to the bundler, but it can be set to any desired address."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 opslen = ops.length;\r\nUserOpInfo[] memory opInfos = new UserOpInfo[](opslen);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Before executing the UserOperations, the EntryPoint will validate each UserOperation. It'll create a ",(0,a.jsx)(t.code,{children:"UserOpInfo"})," array to store the information of each UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"for (uint256 i = 0; i < opslen; i++) {\r\n\tUserOpInfo memory opInfo = opInfos[i];\r\n\t(uint256 validationData, uint256 pmValidationData) = _validatePrepayment(i, ops[i], opInfo);\r\n\t_validateAccountAndPaymasterValidationData(i, validationData, pmValidationData, address(0));\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In order to populate the opInfos from the Bundler, the function will undergo validation check in its loops. In order to save gas it'll be in the ",(0,a.jsx)(t.code,{children:"uncheck"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsxs)(t.p,{children:["After the validation of both the Account and Paymaster, the validation is checked to see if they expire in ",(0,a.jsx)(t.code,{children:"_validateAccountAndPaymasterValidationData"}),". If the validation is successful, the EntryPoint will execute the UserOperations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-validateaccountandpaymastervalidationdata",children:"_validateAccountAndPaymasterValidationData"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 collected = 0;\r\nemit BeforeExecution();\r\n\r\nfor (uint256 i = 0; i < opslen; i++) {\r\n collected += _executeUserOp(i, ops[i], opInfos[i]);\r\n}\r\n\r\n_compensate(beneficiary, collected);\n"})}),"\n",(0,a.jsx)(t.p,{children:"With all validation complete it'll emit an event before execution begins. Then start iterating through each user operation, executing them and adding the gas fees consumed by each operation to the total collected amount. After all operations are executed, it compensates the specified beneficiary with the total collected gas fees, transferring them to the beneficiary's address."}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#wrench-_executeuserop",children:"_executeUserOp"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#dollar-_compensate",children:"_compensate"})]}),"\n",(0,a.jsxs)(t.h2,{id:"heavy_check_mark-_validateprepayment",children:["\u2714\ufe0f"," _validatePrepayment"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validatePrepayment(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory outOpInfo)\r\n\tprivate returns (uint256 validationData, uint256 paymasterValidationData)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," function serves a pivotal role in upholding the integrity and safety of UserOperations within the account abstraction framework."]}),"\n",(0,a.jsx)(t.p,{children:"It takes in three parameters:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"opIndex"}),": The index of the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"userOp"}),": The UserOperation data structure containing essential information about the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo"}),": A UserOpInfo structure used for storing operation-specific data during validation."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = outOpInfo.mUserOp;\r\n_copyUserOpToMemory(userOp, mUserOp);\r\noutOpInfo.userOpHash = getUserOpHash(userOp);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Initially, the function tracks the remaining gas at the start of its execution. Utilizing the built-in Solidity function ",(0,a.jsx)(t.code,{children:"gasleft()"}),", it determines the amount of gas remaining within the current Ethereum transaction. ",(0,a.jsxs)(t.em,{children:["Throughout the call to the EntryPoint, ",(0,a.jsx)(t.code,{children:"gasleft"})," is employed to inform decisions based on the gas supplied by the Bundler."]})," Subsequently, it creates a copy of the data from ",(0,a.jsx)(t.code,{children:"userOp"})," into memory for efficient processing. Following this, it calculates a hash of the UserOperation data using the ",(0,a.jsx)(t.code,{children:"getUserOpHash"})," function. This hash functions as a unique identifier for the operation, facilitating validation processes."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");\n'})}),"\n",(0,a.jsx)(t.p,{children:"This line of code ensures that certain numeric values within the UserOperation data, such as gas limits, do not exceed the maximum value representable by a 120-bit unsigned integer. This safeguard is implemented to mitigate the risk of overflow during subsequent calculations."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 gasUsedByValidateAccountPrepayment;\r\n(uint256 requiredPreFund) = _getRequiredPrefund(mUserOp);\r\n(gasUsedByValidateAccountPrepayment, validationData) = _validateAccountPrepayment(opIndex, userOp, outOpInfo, requiredPreFund);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The function continues by calculating the gas needed to pre-fund the operation. This calculation is based on the UserOperation data and specific conditions defined within the ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"})," function. Furthermore, the function conducts validation checks using ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),". These checks ensure that the account ",(0,a.jsx)(t.em,{children:"(Smart Contract Wallet)"}),", possesses adequate funds and allowances to cover the operation's gas costs."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validateaccountprepayment",children:"_validateAccountPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (mUserOp.paymaster != address(0)) {\r\n\t(context, paymasterValidationData) = _validatePaymasterPrepayment(opIndex, userOp, outOpInfo, requiredPreFund, gasUsedByValidateAccountPrepayment);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This next stage is optional, contingent upon the bundler's inclusion of a paymaster for the UserOperation. ",(0,a.jsx)(t.em,{children:"The paymaster is an integral component in Account Abstraction as it enables users to settle transaction fees such as utilizing ERC-20 tokens rather than native tokens like ETH. Acting as an intermediary, the Paymaster gathers ERC-20 tokens from users and remits ETH to the blockchain for transaction facilitation."})," Therefore, this aspect is a crucial addition to the EntryPoint, permitting the Bundler to cover the UserOperation costs using ERC-20 tokens instead of native tokens such as ETH."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 gasUsed = preGas - gasleft();\r\n\r\nif (userOp.verificationGasLimit < gasUsed) {\r\nrevert FailedOp(opIndex, "AA40 over verificationGasLimit");\r\n}\r\noutOpInfo.prefund = requiredPreFund;\r\noutOpInfo.contextOffset = getOffsetOfMemoryBytes(context);\r\noutOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;\n'})}),"\n",(0,a.jsxs)(t.p,{children:["After completing the necessary gas calculations and validations, the function ensures that the gas utilized during validation does not surpass the specified verification gas limit. Upon success, it finalizes the pre-funding details within the ",(0,a.jsx)(t.code,{children:"outOpInfo"})," structure, encompassing the pre-fund amount, memory context offset, and pre-operation gas usage."]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.prefund"})," is set to the ",(0,a.jsx)(t.code,{children:"requiredPreFund"})," value, which represents the maximum gas fee deducted from the deposit on EP."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.contextOffset"})," is designated as the offset of the context object in memory. Note that the context object is returned by the ",(0,a.jsx)(t.code,{children:"Paymaster.validatePaymasterUserOp"})," call. By storing only the memory offset of the context object, we alleviate the need to pass around the entire context object while invoking internal methods."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.preOpGas"})," is determined as the sum of the total gas used thus far and the ",(0,a.jsx)(t.code,{children:"userOp.preVerificationGas"}),"."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["In summary, ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," assumes the role of guaranteeing the validity and safety of UserOperations within the account abstraction framework. It encompasses crucial tasks such as gas tracking, hashing, validation, and pre-funding calculations, ensuring the seamless and secure execution of operations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#point_right-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validateaccountprepayment",children:"_validateAccountPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"_createSenderIfNeeded(opIndex, opInfo, op.initCode);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This internal method is crucial for validating the operation with a Smart Contract Wallet (SCW). Initially, it calls upon a Factory contract to create the account if required, utilizing ",(0,a.jsx)(t.code,{children:"_createSenderIfNeeded"}),". The Wallet contract generated by this factory must adhere to ",(0,a.jsx)(t.code,{children:"interfaces/IAccount.sol"}),", which includes the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function. This function is essential for validating the UserOp's signature, enabling the EntryPoint to execute operations on a Wallet account."]}),"\n",(0,a.jsxs)(t.p,{children:["Once the Smart Contract Wallet is deemed valid for further validation, the method proceeds to perform calculations on the gas funds and validate the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function on the SCW if and only if ",(0,a.jsx)(t.code,{children:"paymaster == address(0)"}),". This condition signifies that the SCW, either passed or generated, will be responsible for covering the current UserOperation execution(s)."]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"Important stage in handleOps"}),"\r\nAt this point, the EntryPoint call stack should ",(0,a.jsx)(t.code,{children:"handleOps.validatePrePayment._validateAccountPrepayment"}),", where the EntryPoint is validating that the SCW has enough gas to cover the UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try IAccount(sender).validateUserOp{gas : mUserOp.verificationGasLimit}(op, opInfo.userOpHash, missingAccountFunds)\n"})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["There is also the introduction of reverting the entire transaction if validations fail from the SCW or the call runs out of gas. Mainly the ",(0,a.jsx)(t.code,{children:"FailedOp"})," will revert the transaction."]})}),"\n",(0,a.jsxs)(t.p,{children:["Upon successful validation, both ",(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," and ",(0,a.jsx)(t.code,{children:"validationData"})," provided by the SCW through its ",(0,a.jsx)(t.code,{children:"IAccount"})," interface are captured. It is crucial that the validation logic is tailored and executed according to each user's preferences and requirements."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\naddress paymaster = mUserOp.paymaster;\r\nDepositInfo storage paymasterInfo = deposits[paymaster];\r\nuint256 deposit = paymasterInfo.deposit;\r\nif (deposit < requiredPreFund) {\r\n revert FailedOp(opIndex, "AA31 paymaster deposit too low");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Similarly to the ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),", this time, it'll check the paymaster's deposit balance in EP. If there is enough despot compared to the provided, it'll deduct the that the the requiredPreFund from the Paymaster's deposit,"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'MemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 verificationGasLimit = mUserOp.verificationGasLimit;\r\nrequire(verificationGasLimit > gasUsedByValidateAccountPrepayment, "AA41 too little verificationGas");\r\nuint256 gas = verificationGasLimit - gasUsedByValidateAccountPrepayment;\n'})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," calculated by the Account validation, is used to calculate the gas required to pay back the bundler. This is done via ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"}),". Since the EntryPoint is executing the UserOperations, this means that EntryPoint must ensure it has enough gas to execute those UserOperations and in order for the Bundler to obtain the gas, depends on whether a Paymaster is set up or the Smart Contract Wallet provided."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"paymasterInfo.deposit = deposit - requiredPreFund\n"})}),"\n",(0,a.jsxs)(t.p,{children:["After deducting the deposit as mentioned call the validationOp's ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"})," for paymaster of ",(0,a.jsx)(t.code,{children:"interfaces/IPaymaster.sol"})," and with the \xa0",(0,a.jsx)(t.code,{children:"userOp.verificationGasLimit"}),"\xa0as gas limit and return the validation Data."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"IPaymaster(paymaster).validatePaymasterUserOp{gas: gas}(op, opInfo.userOpHash, requiredPreFund) returns (bytes memory _context, uint256 _validationData) \n"})}),"\n",(0,a.jsxs)(t.p,{children:["This will return ",(0,a.jsx)(t.em,{children:"context object"})," and ",(0,a.jsx)(t.code,{children:"validationData"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsxs)(t.h2,{id:"heavy_check_mark-validateaccountandpaymastervalidationdata",children:["\u2714\ufe0f"," validateAccountAndPaymasterValidationData"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validateAccountAndPaymasterValidationData(uint256 opIndex, uint256 validationData, uint256 paymasterValidationData,\r\n address expectedAggregator)\n"})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"validateAccountAndPaymasterValidationData"})," serves to validate the validation data from both the Smart Contract Wallet (SCW) and Paymaster. It verifies if the validation data has expired and reverts the transaction if it has. Notably, in the Ethereum EntryPoint, the ",(0,a.jsx)(t.code,{children:"address(0)"})," represents the ",(0,a.jsx)(t.code,{children:"expectedAggregator"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Before unpacking the validationData, An example of validation data is as follows as taken by ",(0,a.jsx)(t.code,{children:"account-abstraction/ethereum/contracts/TokenPaymaster.sol"}),". ",(0,a.jsx)(t.em,{children:"Note this is just an example, other Paymaster's or SCW validation will have different validation data depending on it implementation."})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"validationResult = _packValidationData(\r\n\tfalse,\r\n\tuint48(cachedPriceTimestamp + tokenPaymasterConfig.priceMaxAge),\r\n\t0\r\n);\n"})}),"\n",(0,a.jsx)(t.p,{children:"The validationData comprises three components, which are essential for the EntryPoint to validate the UserOperation,"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Aggregator: This value signifies the success of the aggregator. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator. For instance, if ",(0,a.jsx)(t.code,{children:"false"})," is provided, it results in the value ",(0,a.jsx)(t.code,{children:"0"}),", indicating success."]}),"\n",(0,a.jsx)(t.li,{children:"ValidUntil: This represents the start time when the signature is valid."}),"\n",(0,a.jsx)(t.li,{children:"ValidAfter: This denotes the end time when the signature is valid."}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["These components collectively determine whether signature verification was successful. The primary implementation of parsing the validationData is outlined in ",(0,a.jsx)(t.code,{children:"Helper.sol"})," within the ",(0,a.jsx)(t.code,{children:"_parseValidationData"})," function. In essence, this method extracts the aggregator value (an ",(0,a.jsx)(t.code,{children:"address"}),"), the validUntil timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),"), and the validAfter timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),") from the validationData. If the validUntil value is 0, as observed in the example provided, it signifies that the signature is valid until the maximum value of ",(0,a.jsx)(t.code,{children:"uint48"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"Since both validationData and paymasterValidationData undergo validation in a similar manner, we'll focus on the paymasterValidationData. The validation process involves comparing these values with the current block timestamp in the EntryPoint to ascertain their validity."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'address pmAggregator;\r\n(pmAggregator, outOfTimeRange) = _getValidationData(paymasterValidationData);\r\nif (pmAggregator != address(0)) {\r\n\trevert FailedOp(opIndex, "AA34 signature error");\r\n}\r\nif (outOfTimeRange) {\r\n\trevert FailedOp(opIndex, "AA32 paymaster expired or not due");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Hence if we go back to the EntryPoint where it'll parse the above ",(0,a.jsx)(t.code,{children:"validationResult"})," as ",(0,a.jsx)(t.code,{children:"paymasterValidationData"})," we see it extracts the ",(0,a.jsx)(t.code,{children:"pmAggregator"})," variable represents the aggregator status obtained from the paymasterValidationData. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator, while ",(0,a.jsx)(t.code,{children:"1"})," implies an expired aggregator. With this, if ",(0,a.jsx)(t.code,{children:"pmAggregator"})," is assigned the value of ",(0,a.jsx)(t.code,{children:"address(0)"}),", it signifies that the aggregator is successful as it has the value of ",(0,a.jsx)(t.code,{children:"0"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Furthermore, validation is conducted by comparing the current block timestamp with the validUntil and validAfter timestamps obtained from the validation data. The ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," variable is set based on whether the current timestamp exceeds the validUntil timestamp or falls before the validAfter timestamp. If ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," is ",(0,a.jsx)(t.code,{children:"true"}),", it indicates that the paymaster has expired or the operation is not yet due."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter;\n"})}),"\n",(0,a.jsx)(t.p,{children:'In summary, the code snippet checks the status of the aggregator and verifies the validity of the paymaster based on timestamps, ensuring that the operation is executed within the designated time range. If any discrepancy is detected, the function reverts the transaction with an appropriate error message, such as "signature error" or "paymaster expired or not due."'}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#point_right-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"numbermarker",children:"numberMarker()"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"//place the NUMBER opcode in the code.\r\n// this is used as a marker during simulation, as this OP is completely banned from the simulated code of the\r\n// account and paymaster.\r\nfunction numberMarker() internal view {\r\n assembly {mstore(0, number())}\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This function is mainly useful for the method ",(0,a.jsx)(t.code,{children:"simulateValidation"}),", for tracing and checkpoints throughout the code. For our purpose, we don't need to really worry about this."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},2345:(e,t,n)=>{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(t.h2,{id:"wrench-_executeuserop",children:["\ud83d\udd27"," _executeUserOp"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _executeUserOp(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory opInfo) \r\n private returns (uint256 collected)\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code begins by retrieving the context from memory. The context is stored as a byte array and contains essential information needed for the ",(0,a.jsx)(t.code,{children:"Paymaster.postOp"})," function."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try this.innerHandleOp(userOp.callData, opInfo, context) returns (\r\n uint256 _actualGasCost\r\n) {\r\n collected = _actualGasCost;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code then attempts to execute the UserOperation by invoking the ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," function. This function, implemented by the Paymaster, takes ",(0,a.jsx)(t.code,{children:"userOp.callData"}),", ",(0,a.jsx)(t.code,{children:"opInfo"}),", and ",(0,a.jsx)(t.code,{children:"context"})," as parameters. Upon invocation, ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," returns the actual gas cost incurred by the operation, which is subsequently added to the ",(0,a.jsx)(t.code,{children:"collected"})," variable."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#innerhandleop",children:"innerHandleOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"innerhandleop",children:"innerHandleOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function innerHandleOp(\r\n bytes memory callData,\r\n UserOpInfo memory opInfo,\r\n bytes calldata context\r\n) external returns (uint256 actualGasCost)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," method is invoked to execute the ",(0,a.jsx)(t.code,{children:"UserOperation"})," calldata on the wallet contract. Leveraging the ",(0,a.jsx)(t.code,{children:"Exec"})," solidity library, available in ",(0,a.jsx)(t.code,{children:"util/Exec.sol"}),", developers gain access to a range of utility functions designed for diverse contract calls. These include regular ",(0,a.jsx)(t.em,{children:"call"}),", ",(0,a.jsx)(t.em,{children:"staticcall"}),", and ",(0,a.jsx)(t.em,{children:"delegatecall"})," functionalities, along with features for retrieving return data and reverting with explicit byte arrays. Such capabilities empower developers to interact flexibly and efficiently with other contracts directly within Solidity contracts, seamlessly managing value transfers and data retrieval. In the following code snippet, ",(0,a.jsx)(t.code,{children:"Exec.call"})," is utilized\u2014a low-level call function\u2014utilizing the calldata provided by ",(0,a.jsx)(t.code,{children:"userOp.callData"}),"."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (callData.length > 0) {\r\n bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);\r\n if (!success) {\r\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\r\n if (result.length > 0) {\r\n emit UserOperationRevertReason(opInfo.userOpHash, mUserOp.sender, mUserOp.nonce, result);\r\n }\r\n mode = IPaymaster.PostOpMode.opReverted;\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"unchecked {\r\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\r\n //note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp)\r\n return _handlePostOp(0, mode, opInfo, context, actualGas);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_handlepostop",children:"_handlePostOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"_handlepostop",children:"_handlePostOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _handlePostOp(uint256 opIndex, IPaymaster.PostOpMode mode, UserOpInfo memory opInfo, bytes memory context, \r\n uint256 actualGas) private returns (uint256 actualGasCost) \n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"address refundAddress;\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 gasPrice = getUserOpGasPrice(mUserOp);\r\n\r\naddress paymaster = mUserOp.paymaster;\r\nif (paymaster == address(0)) {\r\n refundAddress = mUserOp.sender;\r\n} else {\r\n refundAddress = paymaster;\r\n // ...\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["When a paymaster is specified and its validation results in a non-empty context, the surplus amount is reimbursed to the account or paymaster, depending on its involvement in the transaction request. As mentioned, the following code executes the ",(0,a.jsx)(t.code,{children:"IPaymaster"}),"'s ",(0,a.jsx)(t.code,{children:"postOp"})," function, which is another essential method similar to ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"}),"."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["The ",(0,a.jsx)(t.code,{children:"postOp()"})," function acts as a post-execution hook after completing a user operation. It manages tasks to be executed upon successful validation of the user operation, such as handling custom token payments for transaction fees. For example, if a user chooses to pay with an ERC-20 token, the entry point invokes ",(0,a.jsx)(t.code,{children:"postOp()"})," after executing the operation and provides information about gas consumption. Importantly, access to ",(0,a.jsx)(t.code,{children:"postOp()"})," is contingent upon the validation context generated by ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp()"})," not being null. This mechanism simplifies the process of managing token payments and facilitates smooth transaction processing on the blockchain."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'if (context.length > 0) {\r\n actualGasCost = actualGas * gasPrice;\r\n if (mode != IPaymaster.PostOpMode.postOpReverted) {\r\n IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost);\r\n } else {\r\n // solhint-disable-next-line no-empty-blocks\r\n try IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost) {}\r\n catch Error(string memory reason) {\r\n revert FailedOp(opIndex, string.concat("AA50 postOp reverted: ", reason));\r\n }\r\n catch {\r\n revert FailedOp(opIndex, "AA50 postOp revert");\r\n }\r\n }\r\n}\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'actualGas += preGas - gasleft();\r\nactualGasCost = actualGas * gasPrice;\r\nif (opInfo.prefund < actualGasCost) {\r\n revert FailedOp(opIndex, "AA51 prefund below actualGasCost");\r\n}\r\nuint256 refund = opInfo.prefund - actualGasCost;\r\n_incrementDeposit(refundAddress, refund);\r\nbool success = mode == IPaymaster.PostOpMode.opSucceeded;\r\nemit UserOperationEvent(opInfo.userOpHash, mUserOp.sender, mUserOp.paymaster, mUserOp.nonce, success, actualGasCost, actualGas);\n'})}),"\n",(0,a.jsx)(t.p,{children:"After determining the refund address and ensuring that the paymaster context isn't empty, the code proceeds to calculate the actual gas usage and its associated cost during the execution of a smart contract operation. It then verifies whether the pre-funded amount is adequate to cover the gas cost. If not, the transaction is reverted. Any excess pre-funded amount is calculated as a refund and subsequently added to the deposit of the specified address. Finally, the success status of the operation is determined based on the paymaster's mode setting."}),"\n",(0,a.jsx)(t.p,{children:"Additionally:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"_incrementDeposit"})," function in the ",(0,a.jsx)(t.code,{children:"StakeManager"})," contract is invoked to increase the paymaster's deposit by the actual gas cost."]}),"\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"actualGasCost = actualGas * gasPrice"})," calculation determines the actual gas cost of the operation, which is stored as the value of ",(0,a.jsx)(t.code,{children:"collected"})," in the ",(0,a.jsx)(t.code,{children:"handleOps"})," function."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#point_right-handleops",children:"handleOps"})]}),"\n",(0,a.jsxs)(t.h2,{id:"dollar-_compensate",children:["\ud83d\udcb5"," _compensate"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'/**\r\n * compensate the caller\'s beneficiary address with the collected fees of all UserOperations.\r\n * @param beneficiary the address to receive the fees\r\n * @param amount amount to transfer.\r\n */\r\nfunction _compensate(address payable beneficiary, uint256 amount) internal {\r\n require(beneficiary != address(0), "AA90 invalid beneficiary");\r\n (bool success,) = beneficiary.call{value : amount}("");\r\n require(success, "AA91 failed send to beneficiary");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["The final step is to compensate the beneficiary with the collected fees. The collected fees are transferred to the beneficiary address. The beneficiary address can be any address where the bundler wants to receive the refund as provided in the ",(0,a.jsx)(t.code,{children:"handleOps"}),"."]}),"\n",(0,a.jsx)(t.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,a.jsxs)(t.p,{children:["In conclusion, the EntryPoint efficiently executes the bundled UserOperations and ensures fair compensation for the beneficiary by collecting fees. This is the flow of ",(0,a.jsx)(t.code,{children:"handleOp"}),". There is also ",(0,a.jsx)(t.code,{children:"handleAggregatorOp"}),". Note also the EntryPoint extends ",(0,a.jsx)(t.code,{children:"StakeManger"})," found in ",(0,a.jsx)(t.code,{children:"core/StakeManger.sol"})," which as mentioned is responsible for managing ",(0,a.jsx)(t.code,{children:"deposits"})," and stakes to ensure reimbursement for beneficiaries during the execution of handleOps and handleAggregatedOps functions. Deposits represent balances used to cover the costs of UserOperations, while stakes are values locked for a specified duration by paymasters, crucial for the reputation system. To learn more about the EIP proposal and its specifications, you can refer to the official document ",(0,a.jsx)(t.a,{href:"https://eips.ethereum.org/EIPS/eip-4337",children:"here"}),"."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},3456:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{src:t}=e;return(0,a.jsx)("img",{className:"rounded-lg w-full",src:t,alt:"cover"})}},2168:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{url:t}=e;return(0,a.jsx)("iframe",{src:t,height:"400",width:"300",style:{borderRadius:"8px",width:"100%",overflow:"hidden"}})}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>o});var a=n(6540);const s={},i=a.createContext(s);function r(e){const t=a.useContext(i);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),a.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/74ce7958.6ad0d18d.js b/assets/js/74ce7958.6ad0d18d.js deleted file mode 100644 index 3c9c86f..0000000 --- a/assets/js/74ce7958.6ad0d18d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[2905],{5838:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>d,metadata:()=>h,toc:()=>u});var a=n(4848),s=n(8453),i=(n(6540),n(2168)),r=n(3456),o=n(9900),c=n(2345);const d={slug:"/ethereum/erc4337/entrypoint",title:"ERC4337 - Decoding Ethereum's EntryPoint",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["erc4337","account-abstraction","ethereum","entry-point"]},l=void 0,h={permalink:"/doc/blog/ethereum/erc4337/entrypoint",source:"@site/blog/erc4337/entry-point/2024-03-02-index.md",title:"ERC4337 - Decoding Ethereum's EntryPoint",description:"{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"basic",children:"Basic"}),"\n",(0,a.jsxs)(t.p,{children:["Before we go into the details of the EntryPoint, we need to understand the basic flow of how the EntryPoint works. The EntryPoint is a smart contract that is used to execute ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The ",(0,a.jsx)(t.code,{children:"UserOperation"})," is a struct that contains all the necessary information to execute a transaction. The EntryPoint is used to execute multiple UserOperations at once. This is done to save gas costs and to make the execution of transactions more efficient."]}),"\n",(0,a.jsx)(t.h3,{id:"useroperation",children:"UserOperation"}),"\n",(0,a.jsxs)(t.p,{children:["The primary data structure for user interaction within the Account Abstraction framework is encapsulated in ",(0,a.jsx)(t.code,{children:"interfaces/UserOperation.sol"}),". This structure is typically created by the Bundler and transmitted to the EntryPoint contract. The ",(0,a.jsx)(t.code,{children:"UserOperation"})," struct comprises the following fields:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"struct UserOperation {\r\n address sender;\r\n uint256 nonce;\r\n bytes initCode;\r\n bytes callData;\r\n uint256 callGasLimit;\r\n uint256 verificationGasLimit;\r\n uint256 preVerificationGas;\r\n uint256 maxFeePerGas;\r\n uint256 maxPriorityFeePerGas;\r\n bytes paymasterAndData;\r\n bytes signature;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["An example of a ",(0,a.jsx)(t.code,{children:"UserOperation"})," is provided below:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-typescript",children:"const emptyUserOp: UserOperation = {\r\n sender: AddressZero,\r\n callData: '0x',\r\n nonce: 0,\r\n preVerificationGas: 0,\r\n verificationGasLimit: 100000,\r\n callGasLimit: 0,\r\n maxFeePerGas: 0,\r\n maxPriorityFeePerGas: 0,\r\n signature: '0x'\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In contrast to the traditional approach of sending signed transactions to a mempool for validation, the initial step in ERC-4337 involves dispatching an operation in the form of a ",(0,a.jsx)(t.strong,{children:"UserOperation"}),". These operations are then forwarded to an alternative mempool. Users have the capability to dispatch multiple UserOperations concurrently through a Bundler smart contract, referred to as Bundler Transactions."]}),"\n",(0,a.jsx)(t.h3,{id:"entry-point-contract-on-ethereum",children:"Entry Point Contract on Ethereum"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.strong,{children:"EntryPoint"})," (EP) contract on Ethereum, found at ",(0,a.jsx)(t.a,{href:"https://etherscan.io/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",children:"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"}),", is crucial for handling ",(0,a.jsx)(t.code,{children:"bundlerTransactions"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["You can explore this contract using Solidity's IDE ",(0,a.jsx)(t.code,{children:"${SOLIDE_URL}/1/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789)"})]}),"\n",(0,a.jsxs)(t.p,{children:["As of writing this, it's contract version is ",(0,a.jsx)(t.code,{children:"0.6.0"})," and serves as the main hub for processing batches of ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The contract offers two main methods: ",(0,a.jsx)(t.code,{children:"handleOps"})," and ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"}),". We'll focus on ",(0,a.jsx)(t.code,{children:"handleOps"})," for now, leaving ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"})," for later discussion."]}),"\n",(0,a.jsx)(t.h2,{id:"-handleops",children:"\ud83d\udc49 handleOps"}),"\n",(0,a.jsxs)(t.p,{children:["The main flow of a using the EntryPoint typically comes from the ",(0,a.jsx)(t.code,{children:"Bundler"})," contracts which calls, the ",(0,a.jsx)(t.code,{children:"handleOps()"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function handleOps(UserOperation[] calldata ops, address payable beneficiary) public nonReentrant\n"})}),"\n",(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Non-Reentrant Modifier"}),": This modifier prevents reentrancy attacks, ensuring the security of the smart contract."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"UserOperation Array"}),": The ",(0,a.jsx)(t.code,{children:"ops"})," array consists of ",(0,a.jsx)(t.code,{children:"UserOperation"})," objects, stored in ",(0,a.jsx)(t.code,{children:"calldata"}),". These objects hold data passed to the contract's entry point."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Beneficiary Address"}),": The ",(0,a.jsx)(t.code,{children:"beneficiary"})," address is where gas refunds are sent after execution. Typically, this address corresponds to the bundler, but it can be set to any desired address."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 opslen = ops.length;\r\nUserOpInfo[] memory opInfos = new UserOpInfo[](opslen);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Before executing the UserOperations, the EntryPoint will validate each UserOperation. It'll create a ",(0,a.jsx)(t.code,{children:"UserOpInfo"})," array to store the information of each UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"for (uint256 i = 0; i < opslen; i++) {\r\n\tUserOpInfo memory opInfo = opInfos[i];\r\n\t(uint256 validationData, uint256 pmValidationData) = _validatePrepayment(i, ops[i], opInfo);\r\n\t_validateAccountAndPaymasterValidationData(i, validationData, pmValidationData, address(0));\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In order to populate the opInfos from the Bundler, the function will undergo validation check in its loops. In order to save gas it'll be in the ",(0,a.jsx)(t.code,{children:"uncheck"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsxs)(t.p,{children:["After the validation of both the Account and Paymaster, the validation is check if see if they expire in ",(0,a.jsx)(t.code,{children:"_validateAccountAndPaymasterValidationData"}),". If the validation is successful, the EntryPoint will execute the UserOperations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-validateaccountandpaymastervalidationdata",children:"_validateAccountAndPaymasterValidationData"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 collected = 0;\r\nemit BeforeExecution();\r\n\r\nfor (uint256 i = 0; i < opslen; i++) {\r\n collected += _executeUserOp(i, ops[i], opInfos[i]);\r\n}\r\n\r\n_compensate(beneficiary, collected);\n"})}),"\n",(0,a.jsx)(t.p,{children:"With all validation complete it'll emits an event before execution begins. Then start iterating through each user operation, executing them and adding the gas fees consumed by each operation to the total collected amount. After all operations are executed, it compensates the specified beneficiary with the total collected gas fees, transferring them to the beneficiary's address."}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_executeuserop",children:"_executeUserOp"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#-_compensate",children:"_compensate"})]}),"\n",(0,a.jsx)(t.h2,{id:"\ufe0f-_validateprepayment",children:"\u2714\ufe0f _validatePrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validatePrepayment(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory outOpInfo)\r\n\tprivate returns (uint256 validationData, uint256 paymasterValidationData)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," function serves a pivotal role in upholding the integrity and safety of UserOperations within the account abstraction framework."]}),"\n",(0,a.jsx)(t.p,{children:"It takes in three parameters:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"opIndex"}),": The index of the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"userOp"}),": The UserOperation data structure containing essential information about the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo"}),": A UserOpInfo structure used for storing operation-specific data during validation."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = outOpInfo.mUserOp;\r\n_copyUserOpToMemory(userOp, mUserOp);\r\noutOpInfo.userOpHash = getUserOpHash(userOp);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Initially, the function tracks the remaining gas at the start of its execution. Utilizing the built-in Solidity function ",(0,a.jsx)(t.code,{children:"gasleft()"}),", it determines the amount of gas remaining within the current Ethereum transaction. ",(0,a.jsxs)(t.em,{children:["Throughout the call to the EntryPoint, ",(0,a.jsx)(t.code,{children:"gasleft"})," is employed to inform decisions based on the gas supplied by the Bundler."]})," Subsequently, it creates a copy the data from ",(0,a.jsx)(t.code,{children:"userOp"})," into memory for efficient processing. Following this, it calculates a hash of the UserOperation data using the ",(0,a.jsx)(t.code,{children:"getUserOpHash"})," function. This hash functions as a unique identifier for the operation, facilitating validation processes."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");\n'})}),"\n",(0,a.jsx)(t.p,{children:"This line of code ensures that certain numeric values within the UserOperation data, such as gas limits, do not exceed the maximum value representable by a 120-bit unsigned integer. This safeguard is implemented to mitigate the risk of overflow during subsequent calculations."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 gasUsedByValidateAccountPrepayment;\r\n(uint256 requiredPreFund) = _getRequiredPrefund(mUserOp);\r\n(gasUsedByValidateAccountPrepayment, validationData) = _validateAccountPrepayment(opIndex, userOp, outOpInfo, requiredPreFund);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The function continues by calculating the gas needed to pre-fund the operation. This calculation is based on the UserOperation data and specific conditions defined within the ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"})," function. Furthermore, the function conducts validation checks using ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),". These checks ensure that the account ",(0,a.jsx)(t.em,{children:"(Smart Contract Wallet)"})," , possesses adequate funds and allowances to cover the operation's gas costs."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validateaccountprepayment",children:"_validateAccountPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (mUserOp.paymaster != address(0)) {\r\n\t(context, paymasterValidationData) = _validatePaymasterPrepayment(opIndex, userOp, outOpInfo, requiredPreFund, gasUsedByValidateAccountPrepayment);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This next stage is optional, contingent upon the bundler's inclusion of a paymaster for the UserOperation. ",(0,a.jsx)(t.em,{children:"A paymaster, integral component in Account Abstraction as it enables users to settle transaction feees such as utilizing ERC-20 tokens rather than native tokens like ETH. Acting as an intermediary, the Paymaster gathers ERC-20 tokens from users and remits ETH to the blockchain for transaction facilitation."})," Therefore, this aspect is a crucial addition to the EntryPoint, permitting the Bundler to cover the UserOperation costs using ERC-20 tokens instead of native tokens such as ETH."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 gasUsed = preGas - gasleft();\r\n\r\nif (userOp.verificationGasLimit < gasUsed) {\r\nrevert FailedOp(opIndex, "AA40 over verificationGasLimit");\r\n}\r\noutOpInfo.prefund = requiredPreFund;\r\noutOpInfo.contextOffset = getOffsetOfMemoryBytes(context);\r\noutOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;\n'})}),"\n",(0,a.jsxs)(t.p,{children:["After completing the necessary gas calculations and validations, the function ensures that the gas utilized during validation does not surpass the specified verification gas limit. Upon success, it finalizes the pre-funding details within the ",(0,a.jsx)(t.code,{children:"outOpInfo"})," structure, encompassing the pre-fund amount, memory context offset, and pre-operation gas usage."]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.prefund"})," is set to the ",(0,a.jsx)(t.code,{children:"requiredPreFund"})," value, which represents the maximum gas fee deducted from the deposit on EP."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.contextOffset"})," is designated as the offset of the context object in memory. Note that the context object is returned by the ",(0,a.jsx)(t.code,{children:"Paymaster.validatePaymasterUserOp"})," call. By storing only the memory offset of the context object, we alleviate the need to pass around the entire context object while invoking internal methods."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.preOpGas"})," is determined as the sum of the total gas used thus far and the ",(0,a.jsx)(t.code,{children:"userOp.preVerificationGas"}),"."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["In summary, ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," assumes a role of guaranteeing the validity and safety of UserOperations within the account abstraction framework. It encompasses crucial tasks such as gas tracking, hashing, validation, and pre-funding calculations, ensuring the seamless and secure execution of operations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validateaccountprepayment",children:"_validateAccountPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"_createSenderIfNeeded(opIndex, opInfo, op.initCode);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This internal method is crucial for validating the operation with a Smart Contract Wallet (SCW). Initially, it calls upon a Factory contract to create the account if required, utilizing ",(0,a.jsx)(t.code,{children:"_createSenderIfNeeded"}),". The Wallet contract generated by this factory must adhere to ",(0,a.jsx)(t.code,{children:"interfaces/IAccount.sol"}),", which includes the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function. This function is essential for validating the UserOp's signature, enabling the EntryPoint to execute operations on a Wallet account."]}),"\n",(0,a.jsxs)(t.p,{children:["Once the Smart Contract Wallet is deemed valid for further validation, the method proceeds to perform calculations on the gas funds and validate the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function on the SCW if and only if ",(0,a.jsx)(t.code,{children:"paymaster == address(0)"}),". This condition signifies that the SCW, either passed or generated, will be responsible for covering the current UserOperation execution(s)."]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"Important stage in handleOps"}),"\r\nAs this point, the EntryPoint call stack should ",(0,a.jsx)(t.code,{children:"handleOps.validatePrePayment._validateAccountPrepayment"}),", where the EntryPoint is validating that the SCW has enough gas to cover the UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try IAccount(sender).validateUserOp{gas : mUserOp.verificationGasLimit}(op, opInfo.userOpHash, missingAccountFunds)\n"})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["There is also the introducation reverting the entire transaction if validations fails from the SCW or the call runs out of gas. Mainly the ",(0,a.jsx)(t.code,{children:"FailedOp"})," will revert the transaction."]})}),"\n",(0,a.jsxs)(t.p,{children:["Upon successful validation, both ",(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," and ",(0,a.jsx)(t.code,{children:"validationData"})," provided by the SCW through its ",(0,a.jsx)(t.code,{children:"IAccount"})," interface are captured. It is crucial that the validation logic is tailored and executed according to each user's preferences and requirements."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\naddress paymaster = mUserOp.paymaster;\r\nDepositInfo storage paymasterInfo = deposits[paymaster];\r\nuint256 deposit = paymasterInfo.deposit;\r\nif (deposit < requiredPreFund) {\r\n revert FailedOp(opIndex, "AA31 paymaster deposit too low");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Similarly to the ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),", this time, it'll check the paymaster's deposit balance in EP. If there is enough despot compared to the provided , it'll deduct the that the the requiredPreFund from the Paymaster's deposit,"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'MemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 verificationGasLimit = mUserOp.verificationGasLimit;\r\nrequire(verificationGasLimit > gasUsedByValidateAccountPrepayment, "AA41 too little verificationGas");\r\nuint256 gas = verificationGasLimit - gasUsedByValidateAccountPrepayment;\n'})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," calculated by the Account validation, is used to calculate the gas required to pay back the bundler. This is done via ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"}),". Since the EntryPoint is executing the UserOperations, this means that EntryPoint must ensure it has enough gas to execute those UserOperations and in order for the Bundler to obtain the gas, depends on whether a Paymaster is setup or the Smart Contract Wallet provided."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"paymasterInfo.deposit = deposit - requiredPreFund\n"})}),"\n",(0,a.jsxs)(t.p,{children:["After deducting the deposit as mention call the validationOp's ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"})," for paymaster of ",(0,a.jsx)(t.code,{children:"interfaces/IPaymaster.sol"})," and with the \xa0",(0,a.jsx)(t.code,{children:"userOp.verificationGasLimit"}),"\xa0as gas limit and return the validation Data."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"IPaymaster(paymaster).validatePaymasterUserOp{gas: gas}(op, opInfo.userOpHash, requiredPreFund) returns (bytes memory _context, uint256 _validationData) \n"})}),"\n",(0,a.jsxs)(t.p,{children:["This will return ",(0,a.jsx)(t.em,{children:"context object"})," and ",(0,a.jsx)(t.code,{children:"validationData"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsx)(t.h2,{id:"\ufe0f-validateaccountandpaymastervalidationdata",children:"\u2714\ufe0f validateAccountAndPaymasterValidationData"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validateAccountAndPaymasterValidationData(uint256 opIndex, uint256 validationData, uint256 paymasterValidationData,\r\n address expectedAggregator)\n"})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"validateAccountAndPaymasterValidationData"})," serves to validate the validation data from both the Smart Contract Wallet (SCW) and Paymaster. It verifies if the validation data has expired and reverts the transaction if it has. Notably, in the Ethereum EntryPoint, the ",(0,a.jsx)(t.code,{children:"address(0)"})," represents the ",(0,a.jsx)(t.code,{children:"expectedAggregator"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Before unpacking the validationData, An example of validation data is as follows as taken by ",(0,a.jsx)(t.code,{children:"account-abstraction/ethereum/contracts/TokenPaymaster.sol"}),". ",(0,a.jsx)(t.em,{children:"Note this is just an example, other Paymaster's or SCW validation will have different validation data depending on it implementation."})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"validationResult = _packValidationData(\r\n\tfalse,\r\n\tuint48(cachedPriceTimestamp + tokenPaymasterConfig.priceMaxAge),\r\n\t0\r\n);\n"})}),"\n",(0,a.jsx)(t.p,{children:"The validationData comprises three components, which are essential for the EntryPoint to validate the UserOperation,"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Aggregator: This value signifies the success of the aggregator. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator. For instance, if ",(0,a.jsx)(t.code,{children:"false"})," is provided, it results in the value ",(0,a.jsx)(t.code,{children:"0"}),", indicating success."]}),"\n",(0,a.jsx)(t.li,{children:"ValidUntil: This represents the start time when the signature is valid."}),"\n",(0,a.jsx)(t.li,{children:"ValidAfter: This denotes the end time when the signature is valid."}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["These components collectively determine whether signature verification was successful. The primary implementation of parsing the validationData is outlined in ",(0,a.jsx)(t.code,{children:"Helper.sol"})," within the ",(0,a.jsx)(t.code,{children:"_parseValidationData"})," function. In essence, this method extracts the aggregator value (an ",(0,a.jsx)(t.code,{children:"address"}),"), the validUntil timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),"), and the validAfter timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),") from the validationData. If the validUntil value is 0, as observed in the example provided, it signifies that the signature is valid until the maximum value of ",(0,a.jsx)(t.code,{children:"uint48"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"Since both validationData and paymasterValidationData undergo validation in a similar manner, we'll focus on the paymasterValidationData. The validation process involves comparing these values with the current block timestamp in the EntryPoint to ascertain their validity."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'address pmAggregator;\r\n(pmAggregator, outOfTimeRange) = _getValidationData(paymasterValidationData);\r\nif (pmAggregator != address(0)) {\r\n\trevert FailedOp(opIndex, "AA34 signature error");\r\n}\r\nif (outOfTimeRange) {\r\n\trevert FailedOp(opIndex, "AA32 paymaster expired or not due");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Hence if we go back to the EntryPoint where it'll parse the above ",(0,a.jsx)(t.code,{children:"validationResult"})," as ",(0,a.jsx)(t.code,{children:"paymasterValidationData"})," we see it extractsthe ",(0,a.jsx)(t.code,{children:"pmAggregator"})," variable represents the aggregator status obtained from the paymasterValidationData. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator, while ",(0,a.jsx)(t.code,{children:"1"})," implies an expired aggregator. With this, if ",(0,a.jsx)(t.code,{children:"pmAggregator"})," is assigned the value of ",(0,a.jsx)(t.code,{children:"address(0)"}),", it signifies that the aggregator is successful as it has the value of ",(0,a.jsx)(t.code,{children:"0"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Furthermore, validation is conducted by comparing the current block timestamp with the validUntil and validAfter timestamps obtained from the validation data. The ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," variable is set based on whether the current timestamp exceeds the validUntil timestamp or falls before the validAfter timestamp. If ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," is ",(0,a.jsx)(t.code,{children:"true"}),", it indicates that the paymaster has expired or the operation is not yet due."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter;\n"})}),"\n",(0,a.jsx)(t.p,{children:'In summary, the code snippet checks the status of the aggregator and verifies the validity of the paymaster based on timestamps, ensuring that the operation is executed within the designated time range. If any discrepancy is detected, the function reverts the transaction with an appropriate error message, such as "signature error" or "paymaster expired or not due."'}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"numbermarker",children:"numberMarker()"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"//place the NUMBER opcode in the code.\r\n// this is used as a marker during simulation, as this OP is completely banned from the simulated code of the\r\n// account and paymaster.\r\nfunction numberMarker() internal view {\r\n assembly {mstore(0, number())}\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This function is mainly useful for the method ",(0,a.jsx)(t.code,{children:"simulateValidation"}),", for tracing and checkpoints throughout the code. For our purpose, we don't need to really worry about this."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},2345:(e,t,n)=>{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"\ufe0f-_executeuserop",children:"\ud83d\udee0\ufe0f _executeUserOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _executeUserOp(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory opInfo) \r\n private returns (uint256 collected)\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code begins by retrieving the context from memory. The context is stored as a byte array and contains essential information needed for the ",(0,a.jsx)(t.code,{children:"Paymaster.postOp"})," function."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try this.innerHandleOp(userOp.callData, opInfo, context) returns (\r\n uint256 _actualGasCost\r\n) {\r\n collected = _actualGasCost;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code then attempts to execute the UserOperation by invoking the ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," function. This function, implemented by the Paymaster, takes ",(0,a.jsx)(t.code,{children:"userOp.callData"}),", ",(0,a.jsx)(t.code,{children:"opInfo"}),", and ",(0,a.jsx)(t.code,{children:"context"})," as parameters. Upon invocation, ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," returns the actual gas cost incurred by the operation, which is subsequently added to the ",(0,a.jsx)(t.code,{children:"collected"})," variable."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#innerhandleop",children:"innerHandleOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"innerhandleop",children:"innerHandleOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function innerHandleOp(\r\n bytes memory callData,\r\n UserOpInfo memory opInfo,\r\n bytes calldata context\r\n) external returns (uint256 actualGasCost)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," method is invoked to execute the ",(0,a.jsx)(t.code,{children:"UserOperation"})," calldata on the wallet contract. Leveraging the ",(0,a.jsx)(t.code,{children:"Exec"})," solidity library, available in ",(0,a.jsx)(t.code,{children:"util/Exec.sol"}),", developers gain access to a range of utility functions designed for diverse contract calls. These include regular ",(0,a.jsx)(t.em,{children:"call"}),", ",(0,a.jsx)(t.em,{children:"staticcall"}),", and ",(0,a.jsx)(t.em,{children:"delegatecall"})," functionalities, along with features for retrieving return data and reverting with explicit byte arrays. Such capabilities empower developers to interact flexibly and efficiently with other contracts directly within Solidity contracts, seamlessly managing value transfers and data retrieval. In the following code snippet, ",(0,a.jsx)(t.code,{children:"Exec.call"})," is utilized\u2014a low-level call function\u2014utilizing the calldata provided by ",(0,a.jsx)(t.code,{children:"userOp.callData"}),"."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (callData.length > 0) {\r\n bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);\r\n if (!success) {\r\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\r\n if (result.length > 0) {\r\n emit UserOperationRevertReason(opInfo.userOpHash, mUserOp.sender, mUserOp.nonce, result);\r\n }\r\n mode = IPaymaster.PostOpMode.opReverted;\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"unchecked {\r\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\r\n //note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp)\r\n return _handlePostOp(0, mode, opInfo, context, actualGas);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_handlepostop",children:"_handlePostOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"_handlepostop",children:"_handlePostOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _handlePostOp(uint256 opIndex, IPaymaster.PostOpMode mode, UserOpInfo memory opInfo, bytes memory context, \r\n uint256 actualGas) private returns (uint256 actualGasCost) \n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"address refundAddress;\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 gasPrice = getUserOpGasPrice(mUserOp);\r\n\r\naddress paymaster = mUserOp.paymaster;\r\nif (paymaster == address(0)) {\r\n refundAddress = mUserOp.sender;\r\n} else {\r\n refundAddress = paymaster;\r\n // ...\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["When a paymaster is specified and its validation results is a non-empty context, the surplus amount is reimbursed to the account or paymaster, depending on its involvement in the transaction request. As mentioned, the following code executes the ",(0,a.jsx)(t.code,{children:"IPaymaster"}),"'s ",(0,a.jsx)(t.code,{children:"postOp"})," function, which is another essential method similar to ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"}),"."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["The ",(0,a.jsx)(t.code,{children:"postOp()"})," function acts as a post-execution hook after completing a user operation. It manages tasks to be executed upon successful validation of the user operation, such as handling custom token payments for transaction fees. For example, if a user chooses to pay with an ERC-20 token, the entry point invokes ",(0,a.jsx)(t.code,{children:"postOp()"})," after executing the operation and provides information about gas consumption. Importantly, access to ",(0,a.jsx)(t.code,{children:"postOp()"})," is contingent upon the validation context generated by ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp()"})," not being null. This mechanism simplifies the process of managing token payments and facilitates smooth transaction processing on the blockchain."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'if (context.length > 0) {\r\n actualGasCost = actualGas * gasPrice;\r\n if (mode != IPaymaster.PostOpMode.postOpReverted) {\r\n IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost);\r\n } else {\r\n // solhint-disable-next-line no-empty-blocks\r\n try IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost) {}\r\n catch Error(string memory reason) {\r\n revert FailedOp(opIndex, string.concat("AA50 postOp reverted: ", reason));\r\n }\r\n catch {\r\n revert FailedOp(opIndex, "AA50 postOp revert");\r\n }\r\n }\r\n}\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'actualGas += preGas - gasleft();\r\nactualGasCost = actualGas * gasPrice;\r\nif (opInfo.prefund < actualGasCost) {\r\n revert FailedOp(opIndex, "AA51 prefund below actualGasCost");\r\n}\r\nuint256 refund = opInfo.prefund - actualGasCost;\r\n_incrementDeposit(refundAddress, refund);\r\nbool success = mode == IPaymaster.PostOpMode.opSucceeded;\r\nemit UserOperationEvent(opInfo.userOpHash, mUserOp.sender, mUserOp.paymaster, mUserOp.nonce, success, actualGasCost, actualGas);\n'})}),"\n",(0,a.jsx)(t.p,{children:"After determining the refund address and ensuring that the paymaster context isn't empty, the code proceeds to calculate the actual gas usage and its associated cost during the execution of a smart contract operation. It then verifies whether the prefunded amount is adequate to cover the gas cost. If not, the transaction is reverted. Any excess prefunded amount is calculated as a refund and subsequently added to the deposit of the specified address. Finally, the success status of the operation is determined based on the paymaster's mode setting."}),"\n",(0,a.jsx)(t.p,{children:"Additionally:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"_incrementDeposit"})," function in the ",(0,a.jsx)(t.code,{children:"StakeManager"})," contract is invoked to increase the paymaster's deposit by the actual gas cost."]}),"\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"actualGasCost = actualGas * gasPrice"})," calculation determines the actual gas cost of the operation, which is stored as the value of ",(0,a.jsx)(t.code,{children:"collected"})," in the ",(0,a.jsx)(t.code,{children:"handleOps"})," function."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h2,{id:"-_compensate",children:"\ud83d\udcb5 _compensate"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'/**\r\n * compensate the caller\'s beneficiary address with the collected fees of all UserOperations.\r\n * @param beneficiary the address to receive the fees\r\n * @param amount amount to transfer.\r\n */\r\nfunction _compensate(address payable beneficiary, uint256 amount) internal {\r\n require(beneficiary != address(0), "AA90 invalid beneficiary");\r\n (bool success,) = beneficiary.call{value : amount}("");\r\n require(success, "AA91 failed send to beneficiary");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["The final step is to compensate the beneficiary with the collected fees. The collected fees are transferred to the beneficiary address. The beneficiary address can be any address where the bundler wants to receive the refund as provided in the ",(0,a.jsx)(t.code,{children:"handleOps"}),"."]}),"\n",(0,a.jsx)(t.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,a.jsxs)(t.p,{children:["In conclusion, the EntryPoint efficiently executes the bundled UserOperations and ensures fair compensation for the beneficiary by collecting fees. This is the flow of ",(0,a.jsx)(t.code,{children:"handleOp"}),". There is also ",(0,a.jsx)(t.code,{children:"handleAggregatorOp"}),". Note also the EntryPoint extends ",(0,a.jsx)(t.code,{children:"StakeManger"})," found in ",(0,a.jsx)(t.code,{children:"core/StakeManger.sol"})," which as mentioned is responsible for managing ",(0,a.jsx)(t.code,{children:"deposits"})," and stakes to ensure reimbursement for beneficiaries during the execution of handleOps and handleAggregatedOps functions. Deposits represent balances used to cover the costs of UserOperations, while stakes are values locked for a specified duration by paymasters, crucial for the reputation system. To learn more about the EIP proposal and its specifications, you can refer to the official document ",(0,a.jsx)(t.a,{href:"https://eips.ethereum.org/EIPS/eip-4337",children:"here"}),"."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},3456:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{src:t}=e;return(0,a.jsx)("img",{className:"rounded-lg w-full",src:t,alt:"cover"})}},2168:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{url:t}=e;return(0,a.jsx)("iframe",{src:t,height:"400",width:"300",style:{borderRadius:"8px",width:"100%",overflow:"hidden"}})}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>o});var a=n(6540);const s={},i=a.createContext(s);function r(e){const t=a.useContext(i);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),a.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/814f3328.54fc9116.js b/assets/js/814f3328.54fc9116.js new file mode 100644 index 0000000..b789675 --- /dev/null +++ b/assets/js/814f3328.54fc9116.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[7472],{5513:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"ERC4337 - Paymaster","permalink":"/doc/blog/ethereum/erc4337/paymaster","unlisted":false},{"title":"ERC4337 - Decoding Ethereum\'s EntryPoint","permalink":"/doc/blog/ethereum/erc4337/entrypoint","unlisted":false},{"title":"Welcome","permalink":"/doc/blog/welcome","unlisted":false}]}')}}]); \ No newline at end of file diff --git a/assets/js/814f3328.7350f453.js b/assets/js/814f3328.7350f453.js deleted file mode 100644 index c7e7cd3..0000000 --- a/assets/js/814f3328.7350f453.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[7472],{5513:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"ERC4337 - Decoding Ethereum\'s EntryPoint","permalink":"/doc/blog/ethereum/erc4337/entrypoint","unlisted":false},{"title":"ERC4337 - Paymaster","permalink":"/doc/blog/ethereum/erc4337/paymaster","unlisted":false},{"title":"Welcome","permalink":"/doc/blog/welcome","unlisted":false}]}')}}]); \ No newline at end of file diff --git a/assets/js/a0834fcb.3b8ccbcf.js b/assets/js/a0834fcb.3b8ccbcf.js new file mode 100644 index 0000000..ed93e23 --- /dev/null +++ b/assets/js/a0834fcb.3b8ccbcf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8390],{890:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>d,metadata:()=>h,toc:()=>u});var a=n(4848),s=n(8453),i=(n(6540),n(2168)),r=n(3456),o=n(9900),c=n(2345);const d={slug:"/ethereum/erc4337/entrypoint",title:"ERC4337 - Decoding Ethereum's EntryPoint",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["erc4337","account-abstraction","ethereum","entry-point"]},l=void 0,h={permalink:"/doc/blog/ethereum/erc4337/entrypoint",source:"@site/blog/erc4337/entry-point/2024-03-02-index.md",title:"ERC4337 - Decoding Ethereum's EntryPoint",description:"{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"basic",children:"Basic"}),"\n",(0,a.jsxs)(t.p,{children:["Before we go into the details of the EntryPoint, we need to understand the basic flow of how the EntryPoint works. The EntryPoint is a smart contract that is used to execute ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The ",(0,a.jsx)(t.code,{children:"UserOperation"})," is a struct that contains all the necessary information to execute a transaction. The EntryPoint is used to execute multiple UserOperations at once. This is done to save gas costs and to make the execution of transactions more efficient."]}),"\n",(0,a.jsx)(t.h3,{id:"useroperation",children:"UserOperation"}),"\n",(0,a.jsxs)(t.p,{children:["The primary data structure for user interaction within the Account Abstraction framework is encapsulated in ",(0,a.jsx)(t.code,{children:"interfaces/UserOperation.sol"}),". This structure is typically created by the Bundler and transmitted to the EntryPoint contract. The ",(0,a.jsx)(t.code,{children:"UserOperation"})," struct comprises the following fields:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"struct UserOperation {\r\n address sender;\r\n uint256 nonce;\r\n bytes initCode;\r\n bytes callData;\r\n uint256 callGasLimit;\r\n uint256 verificationGasLimit;\r\n uint256 preVerificationGas;\r\n uint256 maxFeePerGas;\r\n uint256 maxPriorityFeePerGas;\r\n bytes paymasterAndData;\r\n bytes signature;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["An example of a ",(0,a.jsx)(t.code,{children:"UserOperation"})," is provided below:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-typescript",children:"const emptyUserOp: UserOperation = {\r\n sender: AddressZero,\r\n callData: '0x',\r\n nonce: 0,\r\n preVerificationGas: 0,\r\n verificationGasLimit: 100000,\r\n callGasLimit: 0,\r\n maxFeePerGas: 0,\r\n maxPriorityFeePerGas: 0,\r\n signature: '0x'\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In contrast to the traditional approach of sending signed transactions to a mempool for validation, the initial step in ERC-4337 involves dispatching an operation in the form of a ",(0,a.jsx)(t.strong,{children:"UserOperation"}),". These operations are then forwarded to an alternative mempool. Users have the capability to dispatch multiple UserOperations concurrently through a Bundler smart contract, referred to as Bundler Transactions."]}),"\n",(0,a.jsx)(t.h3,{id:"entry-point-contract-on-ethereum",children:"Entry Point Contract on Ethereum"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.strong,{children:"EntryPoint"})," (EP) contract on Ethereum, found at ",(0,a.jsx)(t.a,{href:"https://etherscan.io/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",children:"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"}),", is crucial for handling ",(0,a.jsx)(t.code,{children:"bundlerTransactions"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["You can explore this contract using Solidity's IDE ",(0,a.jsx)(t.code,{children:"${SOLIDE_URL}/1/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789)"})]}),"\n",(0,a.jsxs)(t.p,{children:["As of writing this, its contract version is ",(0,a.jsx)(t.code,{children:"0.6.0"})," and serves as the main hub for processing batches of ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The contract offers two main methods: ",(0,a.jsx)(t.code,{children:"handleOps"})," and ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"}),". We'll focus on ",(0,a.jsx)(t.code,{children:"handleOps"})," for now, leaving ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"})," for later discussion."]}),"\n",(0,a.jsxs)(t.h2,{id:"point_right-handleops",children:["\ud83d\udc49"," handleOps"]}),"\n",(0,a.jsxs)(t.p,{children:["The main flow of using the EntryPoint typically comes from the ",(0,a.jsx)(t.code,{children:"Bundler"})," contracts which are called the ",(0,a.jsx)(t.code,{children:"handleOps()"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function handleOps(UserOperation[] calldata ops, address payable beneficiary) public nonReentrant\n"})}),"\n",(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Non-Reentrant Modifier"}),": This modifier prevents reentrancy attacks, ensuring the security of the smart contract."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"UserOperation Array"}),": The ",(0,a.jsx)(t.code,{children:"ops"})," array consists of ",(0,a.jsx)(t.code,{children:"UserOperation"})," objects, stored in ",(0,a.jsx)(t.code,{children:"calldata"}),". These objects hold data passed to the contract's entry point."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Beneficiary Address"}),": The ",(0,a.jsx)(t.code,{children:"beneficiary"})," address is where gas refunds are sent after execution. Typically, this address corresponds to the bundler, but it can be set to any desired address."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 opslen = ops.length;\r\nUserOpInfo[] memory opInfos = new UserOpInfo[](opslen);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Before executing the UserOperations, the EntryPoint will validate each UserOperation. It'll create a ",(0,a.jsx)(t.code,{children:"UserOpInfo"})," array to store the information of each UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"for (uint256 i = 0; i < opslen; i++) {\r\n\tUserOpInfo memory opInfo = opInfos[i];\r\n\t(uint256 validationData, uint256 pmValidationData) = _validatePrepayment(i, ops[i], opInfo);\r\n\t_validateAccountAndPaymasterValidationData(i, validationData, pmValidationData, address(0));\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In order to populate the opInfos from the Bundler, the function will undergo validation check in its loops. In order to save gas it'll be in the ",(0,a.jsx)(t.code,{children:"uncheck"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsxs)(t.p,{children:["After the validation of both the Account and Paymaster, the validation is checked to see if they expire in ",(0,a.jsx)(t.code,{children:"_validateAccountAndPaymasterValidationData"}),". If the validation is successful, the EntryPoint will execute the UserOperations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-validateaccountandpaymastervalidationdata",children:"_validateAccountAndPaymasterValidationData"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 collected = 0;\r\nemit BeforeExecution();\r\n\r\nfor (uint256 i = 0; i < opslen; i++) {\r\n collected += _executeUserOp(i, ops[i], opInfos[i]);\r\n}\r\n\r\n_compensate(beneficiary, collected);\n"})}),"\n",(0,a.jsx)(t.p,{children:"With all validation complete it'll emit an event before execution begins. Then start iterating through each user operation, executing them and adding the gas fees consumed by each operation to the total collected amount. After all operations are executed, it compensates the specified beneficiary with the total collected gas fees, transferring them to the beneficiary's address."}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#wrench-_executeuserop",children:"_executeUserOp"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#dollar-_compensate",children:"_compensate"})]}),"\n",(0,a.jsxs)(t.h2,{id:"heavy_check_mark-_validateprepayment",children:["\u2714\ufe0f"," _validatePrepayment"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validatePrepayment(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory outOpInfo)\r\n\tprivate returns (uint256 validationData, uint256 paymasterValidationData)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," function serves a pivotal role in upholding the integrity and safety of UserOperations within the account abstraction framework."]}),"\n",(0,a.jsx)(t.p,{children:"It takes in three parameters:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"opIndex"}),": The index of the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"userOp"}),": The UserOperation data structure containing essential information about the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo"}),": A UserOpInfo structure used for storing operation-specific data during validation."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = outOpInfo.mUserOp;\r\n_copyUserOpToMemory(userOp, mUserOp);\r\noutOpInfo.userOpHash = getUserOpHash(userOp);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Initially, the function tracks the remaining gas at the start of its execution. Utilizing the built-in Solidity function ",(0,a.jsx)(t.code,{children:"gasleft()"}),", it determines the amount of gas remaining within the current Ethereum transaction. ",(0,a.jsxs)(t.em,{children:["Throughout the call to the EntryPoint, ",(0,a.jsx)(t.code,{children:"gasleft"})," is employed to inform decisions based on the gas supplied by the Bundler."]})," Subsequently, it creates a copy of the data from ",(0,a.jsx)(t.code,{children:"userOp"})," into memory for efficient processing. Following this, it calculates a hash of the UserOperation data using the ",(0,a.jsx)(t.code,{children:"getUserOpHash"})," function. This hash functions as a unique identifier for the operation, facilitating validation processes."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");\n'})}),"\n",(0,a.jsx)(t.p,{children:"This line of code ensures that certain numeric values within the UserOperation data, such as gas limits, do not exceed the maximum value representable by a 120-bit unsigned integer. This safeguard is implemented to mitigate the risk of overflow during subsequent calculations."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 gasUsedByValidateAccountPrepayment;\r\n(uint256 requiredPreFund) = _getRequiredPrefund(mUserOp);\r\n(gasUsedByValidateAccountPrepayment, validationData) = _validateAccountPrepayment(opIndex, userOp, outOpInfo, requiredPreFund);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The function continues by calculating the gas needed to pre-fund the operation. This calculation is based on the UserOperation data and specific conditions defined within the ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"})," function. Furthermore, the function conducts validation checks using ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),". These checks ensure that the account ",(0,a.jsx)(t.em,{children:"(Smart Contract Wallet)"}),", possesses adequate funds and allowances to cover the operation's gas costs."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validateaccountprepayment",children:"_validateAccountPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (mUserOp.paymaster != address(0)) {\r\n\t(context, paymasterValidationData) = _validatePaymasterPrepayment(opIndex, userOp, outOpInfo, requiredPreFund, gasUsedByValidateAccountPrepayment);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This next stage is optional, contingent upon the bundler's inclusion of a paymaster for the UserOperation. ",(0,a.jsx)(t.em,{children:"The paymaster is an integral component in Account Abstraction as it enables users to settle transaction fees such as utilizing ERC-20 tokens rather than native tokens like ETH. Acting as an intermediary, the Paymaster gathers ERC-20 tokens from users and remits ETH to the blockchain for transaction facilitation."})," Therefore, this aspect is a crucial addition to the EntryPoint, permitting the Bundler to cover the UserOperation costs using ERC-20 tokens instead of native tokens such as ETH."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 gasUsed = preGas - gasleft();\r\n\r\nif (userOp.verificationGasLimit < gasUsed) {\r\nrevert FailedOp(opIndex, "AA40 over verificationGasLimit");\r\n}\r\noutOpInfo.prefund = requiredPreFund;\r\noutOpInfo.contextOffset = getOffsetOfMemoryBytes(context);\r\noutOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;\n'})}),"\n",(0,a.jsxs)(t.p,{children:["After completing the necessary gas calculations and validations, the function ensures that the gas utilized during validation does not surpass the specified verification gas limit. Upon success, it finalizes the pre-funding details within the ",(0,a.jsx)(t.code,{children:"outOpInfo"})," structure, encompassing the pre-fund amount, memory context offset, and pre-operation gas usage."]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.prefund"})," is set to the ",(0,a.jsx)(t.code,{children:"requiredPreFund"})," value, which represents the maximum gas fee deducted from the deposit on EP."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.contextOffset"})," is designated as the offset of the context object in memory. Note that the context object is returned by the ",(0,a.jsx)(t.code,{children:"Paymaster.validatePaymasterUserOp"})," call. By storing only the memory offset of the context object, we alleviate the need to pass around the entire context object while invoking internal methods."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.preOpGas"})," is determined as the sum of the total gas used thus far and the ",(0,a.jsx)(t.code,{children:"userOp.preVerificationGas"}),"."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["In summary, ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," assumes the role of guaranteeing the validity and safety of UserOperations within the account abstraction framework. It encompasses crucial tasks such as gas tracking, hashing, validation, and pre-funding calculations, ensuring the seamless and secure execution of operations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#point_right-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validateaccountprepayment",children:"_validateAccountPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"_createSenderIfNeeded(opIndex, opInfo, op.initCode);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This internal method is crucial for validating the operation with a Smart Contract Wallet (SCW). Initially, it calls upon a Factory contract to create the account if required, utilizing ",(0,a.jsx)(t.code,{children:"_createSenderIfNeeded"}),". The Wallet contract generated by this factory must adhere to ",(0,a.jsx)(t.code,{children:"interfaces/IAccount.sol"}),", which includes the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function. This function is essential for validating the UserOp's signature, enabling the EntryPoint to execute operations on a Wallet account."]}),"\n",(0,a.jsxs)(t.p,{children:["Once the Smart Contract Wallet is deemed valid for further validation, the method proceeds to perform calculations on the gas funds and validate the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function on the SCW if and only if ",(0,a.jsx)(t.code,{children:"paymaster == address(0)"}),". This condition signifies that the SCW, either passed or generated, will be responsible for covering the current UserOperation execution(s)."]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"Important stage in handleOps"}),"\r\nAt this point, the EntryPoint call stack should ",(0,a.jsx)(t.code,{children:"handleOps.validatePrePayment._validateAccountPrepayment"}),", where the EntryPoint is validating that the SCW has enough gas to cover the UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try IAccount(sender).validateUserOp{gas : mUserOp.verificationGasLimit}(op, opInfo.userOpHash, missingAccountFunds)\n"})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["There is also the introduction of reverting the entire transaction if validations fail from the SCW or the call runs out of gas. Mainly the ",(0,a.jsx)(t.code,{children:"FailedOp"})," will revert the transaction."]})}),"\n",(0,a.jsxs)(t.p,{children:["Upon successful validation, both ",(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," and ",(0,a.jsx)(t.code,{children:"validationData"})," provided by the SCW through its ",(0,a.jsx)(t.code,{children:"IAccount"})," interface are captured. It is crucial that the validation logic is tailored and executed according to each user's preferences and requirements."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\naddress paymaster = mUserOp.paymaster;\r\nDepositInfo storage paymasterInfo = deposits[paymaster];\r\nuint256 deposit = paymasterInfo.deposit;\r\nif (deposit < requiredPreFund) {\r\n revert FailedOp(opIndex, "AA31 paymaster deposit too low");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Similarly to the ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),", this time, it'll check the paymaster's deposit balance in EP. If there is enough despot compared to the provided, it'll deduct the that the the requiredPreFund from the Paymaster's deposit,"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'MemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 verificationGasLimit = mUserOp.verificationGasLimit;\r\nrequire(verificationGasLimit > gasUsedByValidateAccountPrepayment, "AA41 too little verificationGas");\r\nuint256 gas = verificationGasLimit - gasUsedByValidateAccountPrepayment;\n'})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," calculated by the Account validation, is used to calculate the gas required to pay back the bundler. This is done via ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"}),". Since the EntryPoint is executing the UserOperations, this means that EntryPoint must ensure it has enough gas to execute those UserOperations and in order for the Bundler to obtain the gas, depends on whether a Paymaster is set up or the Smart Contract Wallet provided."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"paymasterInfo.deposit = deposit - requiredPreFund\n"})}),"\n",(0,a.jsxs)(t.p,{children:["After deducting the deposit as mentioned call the validationOp's ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"})," for paymaster of ",(0,a.jsx)(t.code,{children:"interfaces/IPaymaster.sol"})," and with the \xa0",(0,a.jsx)(t.code,{children:"userOp.verificationGasLimit"}),"\xa0as gas limit and return the validation Data."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"IPaymaster(paymaster).validatePaymasterUserOp{gas: gas}(op, opInfo.userOpHash, requiredPreFund) returns (bytes memory _context, uint256 _validationData) \n"})}),"\n",(0,a.jsxs)(t.p,{children:["This will return ",(0,a.jsx)(t.em,{children:"context object"})," and ",(0,a.jsx)(t.code,{children:"validationData"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#heavy_check_mark-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsxs)(t.h2,{id:"heavy_check_mark-validateaccountandpaymastervalidationdata",children:["\u2714\ufe0f"," validateAccountAndPaymasterValidationData"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validateAccountAndPaymasterValidationData(uint256 opIndex, uint256 validationData, uint256 paymasterValidationData,\r\n address expectedAggregator)\n"})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"validateAccountAndPaymasterValidationData"})," serves to validate the validation data from both the Smart Contract Wallet (SCW) and Paymaster. It verifies if the validation data has expired and reverts the transaction if it has. Notably, in the Ethereum EntryPoint, the ",(0,a.jsx)(t.code,{children:"address(0)"})," represents the ",(0,a.jsx)(t.code,{children:"expectedAggregator"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Before unpacking the validationData, An example of validation data is as follows as taken by ",(0,a.jsx)(t.code,{children:"account-abstraction/ethereum/contracts/TokenPaymaster.sol"}),". ",(0,a.jsx)(t.em,{children:"Note this is just an example, other Paymaster's or SCW validation will have different validation data depending on it implementation."})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"validationResult = _packValidationData(\r\n\tfalse,\r\n\tuint48(cachedPriceTimestamp + tokenPaymasterConfig.priceMaxAge),\r\n\t0\r\n);\n"})}),"\n",(0,a.jsx)(t.p,{children:"The validationData comprises three components, which are essential for the EntryPoint to validate the UserOperation,"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Aggregator: This value signifies the success of the aggregator. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator. For instance, if ",(0,a.jsx)(t.code,{children:"false"})," is provided, it results in the value ",(0,a.jsx)(t.code,{children:"0"}),", indicating success."]}),"\n",(0,a.jsx)(t.li,{children:"ValidUntil: This represents the start time when the signature is valid."}),"\n",(0,a.jsx)(t.li,{children:"ValidAfter: This denotes the end time when the signature is valid."}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["These components collectively determine whether signature verification was successful. The primary implementation of parsing the validationData is outlined in ",(0,a.jsx)(t.code,{children:"Helper.sol"})," within the ",(0,a.jsx)(t.code,{children:"_parseValidationData"})," function. In essence, this method extracts the aggregator value (an ",(0,a.jsx)(t.code,{children:"address"}),"), the validUntil timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),"), and the validAfter timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),") from the validationData. If the validUntil value is 0, as observed in the example provided, it signifies that the signature is valid until the maximum value of ",(0,a.jsx)(t.code,{children:"uint48"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"Since both validationData and paymasterValidationData undergo validation in a similar manner, we'll focus on the paymasterValidationData. The validation process involves comparing these values with the current block timestamp in the EntryPoint to ascertain their validity."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'address pmAggregator;\r\n(pmAggregator, outOfTimeRange) = _getValidationData(paymasterValidationData);\r\nif (pmAggregator != address(0)) {\r\n\trevert FailedOp(opIndex, "AA34 signature error");\r\n}\r\nif (outOfTimeRange) {\r\n\trevert FailedOp(opIndex, "AA32 paymaster expired or not due");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Hence if we go back to the EntryPoint where it'll parse the above ",(0,a.jsx)(t.code,{children:"validationResult"})," as ",(0,a.jsx)(t.code,{children:"paymasterValidationData"})," we see it extracts the ",(0,a.jsx)(t.code,{children:"pmAggregator"})," variable represents the aggregator status obtained from the paymasterValidationData. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator, while ",(0,a.jsx)(t.code,{children:"1"})," implies an expired aggregator. With this, if ",(0,a.jsx)(t.code,{children:"pmAggregator"})," is assigned the value of ",(0,a.jsx)(t.code,{children:"address(0)"}),", it signifies that the aggregator is successful as it has the value of ",(0,a.jsx)(t.code,{children:"0"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Furthermore, validation is conducted by comparing the current block timestamp with the validUntil and validAfter timestamps obtained from the validation data. The ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," variable is set based on whether the current timestamp exceeds the validUntil timestamp or falls before the validAfter timestamp. If ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," is ",(0,a.jsx)(t.code,{children:"true"}),", it indicates that the paymaster has expired or the operation is not yet due."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter;\n"})}),"\n",(0,a.jsx)(t.p,{children:'In summary, the code snippet checks the status of the aggregator and verifies the validity of the paymaster based on timestamps, ensuring that the operation is executed within the designated time range. If any discrepancy is detected, the function reverts the transaction with an appropriate error message, such as "signature error" or "paymaster expired or not due."'}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#point_right-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"numbermarker",children:"numberMarker()"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"//place the NUMBER opcode in the code.\r\n// this is used as a marker during simulation, as this OP is completely banned from the simulated code of the\r\n// account and paymaster.\r\nfunction numberMarker() internal view {\r\n assembly {mstore(0, number())}\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This function is mainly useful for the method ",(0,a.jsx)(t.code,{children:"simulateValidation"}),", for tracing and checkpoints throughout the code. For our purpose, we don't need to really worry about this."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},2345:(e,t,n)=>{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(t.h2,{id:"wrench-_executeuserop",children:["\ud83d\udd27"," _executeUserOp"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _executeUserOp(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory opInfo) \r\n private returns (uint256 collected)\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code begins by retrieving the context from memory. The context is stored as a byte array and contains essential information needed for the ",(0,a.jsx)(t.code,{children:"Paymaster.postOp"})," function."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try this.innerHandleOp(userOp.callData, opInfo, context) returns (\r\n uint256 _actualGasCost\r\n) {\r\n collected = _actualGasCost;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code then attempts to execute the UserOperation by invoking the ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," function. This function, implemented by the Paymaster, takes ",(0,a.jsx)(t.code,{children:"userOp.callData"}),", ",(0,a.jsx)(t.code,{children:"opInfo"}),", and ",(0,a.jsx)(t.code,{children:"context"})," as parameters. Upon invocation, ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," returns the actual gas cost incurred by the operation, which is subsequently added to the ",(0,a.jsx)(t.code,{children:"collected"})," variable."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#innerhandleop",children:"innerHandleOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"innerhandleop",children:"innerHandleOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function innerHandleOp(\r\n bytes memory callData,\r\n UserOpInfo memory opInfo,\r\n bytes calldata context\r\n) external returns (uint256 actualGasCost)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," method is invoked to execute the ",(0,a.jsx)(t.code,{children:"UserOperation"})," calldata on the wallet contract. Leveraging the ",(0,a.jsx)(t.code,{children:"Exec"})," solidity library, available in ",(0,a.jsx)(t.code,{children:"util/Exec.sol"}),", developers gain access to a range of utility functions designed for diverse contract calls. These include regular ",(0,a.jsx)(t.em,{children:"call"}),", ",(0,a.jsx)(t.em,{children:"staticcall"}),", and ",(0,a.jsx)(t.em,{children:"delegatecall"})," functionalities, along with features for retrieving return data and reverting with explicit byte arrays. Such capabilities empower developers to interact flexibly and efficiently with other contracts directly within Solidity contracts, seamlessly managing value transfers and data retrieval. In the following code snippet, ",(0,a.jsx)(t.code,{children:"Exec.call"})," is utilized\u2014a low-level call function\u2014utilizing the calldata provided by ",(0,a.jsx)(t.code,{children:"userOp.callData"}),"."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (callData.length > 0) {\r\n bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);\r\n if (!success) {\r\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\r\n if (result.length > 0) {\r\n emit UserOperationRevertReason(opInfo.userOpHash, mUserOp.sender, mUserOp.nonce, result);\r\n }\r\n mode = IPaymaster.PostOpMode.opReverted;\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"unchecked {\r\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\r\n //note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp)\r\n return _handlePostOp(0, mode, opInfo, context, actualGas);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_handlepostop",children:"_handlePostOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"_handlepostop",children:"_handlePostOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _handlePostOp(uint256 opIndex, IPaymaster.PostOpMode mode, UserOpInfo memory opInfo, bytes memory context, \r\n uint256 actualGas) private returns (uint256 actualGasCost) \n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"address refundAddress;\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 gasPrice = getUserOpGasPrice(mUserOp);\r\n\r\naddress paymaster = mUserOp.paymaster;\r\nif (paymaster == address(0)) {\r\n refundAddress = mUserOp.sender;\r\n} else {\r\n refundAddress = paymaster;\r\n // ...\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["When a paymaster is specified and its validation results in a non-empty context, the surplus amount is reimbursed to the account or paymaster, depending on its involvement in the transaction request. As mentioned, the following code executes the ",(0,a.jsx)(t.code,{children:"IPaymaster"}),"'s ",(0,a.jsx)(t.code,{children:"postOp"})," function, which is another essential method similar to ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"}),"."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["The ",(0,a.jsx)(t.code,{children:"postOp()"})," function acts as a post-execution hook after completing a user operation. It manages tasks to be executed upon successful validation of the user operation, such as handling custom token payments for transaction fees. For example, if a user chooses to pay with an ERC-20 token, the entry point invokes ",(0,a.jsx)(t.code,{children:"postOp()"})," after executing the operation and provides information about gas consumption. Importantly, access to ",(0,a.jsx)(t.code,{children:"postOp()"})," is contingent upon the validation context generated by ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp()"})," not being null. This mechanism simplifies the process of managing token payments and facilitates smooth transaction processing on the blockchain."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'if (context.length > 0) {\r\n actualGasCost = actualGas * gasPrice;\r\n if (mode != IPaymaster.PostOpMode.postOpReverted) {\r\n IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost);\r\n } else {\r\n // solhint-disable-next-line no-empty-blocks\r\n try IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost) {}\r\n catch Error(string memory reason) {\r\n revert FailedOp(opIndex, string.concat("AA50 postOp reverted: ", reason));\r\n }\r\n catch {\r\n revert FailedOp(opIndex, "AA50 postOp revert");\r\n }\r\n }\r\n}\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'actualGas += preGas - gasleft();\r\nactualGasCost = actualGas * gasPrice;\r\nif (opInfo.prefund < actualGasCost) {\r\n revert FailedOp(opIndex, "AA51 prefund below actualGasCost");\r\n}\r\nuint256 refund = opInfo.prefund - actualGasCost;\r\n_incrementDeposit(refundAddress, refund);\r\nbool success = mode == IPaymaster.PostOpMode.opSucceeded;\r\nemit UserOperationEvent(opInfo.userOpHash, mUserOp.sender, mUserOp.paymaster, mUserOp.nonce, success, actualGasCost, actualGas);\n'})}),"\n",(0,a.jsx)(t.p,{children:"After determining the refund address and ensuring that the paymaster context isn't empty, the code proceeds to calculate the actual gas usage and its associated cost during the execution of a smart contract operation. It then verifies whether the pre-funded amount is adequate to cover the gas cost. If not, the transaction is reverted. Any excess pre-funded amount is calculated as a refund and subsequently added to the deposit of the specified address. Finally, the success status of the operation is determined based on the paymaster's mode setting."}),"\n",(0,a.jsx)(t.p,{children:"Additionally:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"_incrementDeposit"})," function in the ",(0,a.jsx)(t.code,{children:"StakeManager"})," contract is invoked to increase the paymaster's deposit by the actual gas cost."]}),"\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"actualGasCost = actualGas * gasPrice"})," calculation determines the actual gas cost of the operation, which is stored as the value of ",(0,a.jsx)(t.code,{children:"collected"})," in the ",(0,a.jsx)(t.code,{children:"handleOps"})," function."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#point_right-handleops",children:"handleOps"})]}),"\n",(0,a.jsxs)(t.h2,{id:"dollar-_compensate",children:["\ud83d\udcb5"," _compensate"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'/**\r\n * compensate the caller\'s beneficiary address with the collected fees of all UserOperations.\r\n * @param beneficiary the address to receive the fees\r\n * @param amount amount to transfer.\r\n */\r\nfunction _compensate(address payable beneficiary, uint256 amount) internal {\r\n require(beneficiary != address(0), "AA90 invalid beneficiary");\r\n (bool success,) = beneficiary.call{value : amount}("");\r\n require(success, "AA91 failed send to beneficiary");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["The final step is to compensate the beneficiary with the collected fees. The collected fees are transferred to the beneficiary address. The beneficiary address can be any address where the bundler wants to receive the refund as provided in the ",(0,a.jsx)(t.code,{children:"handleOps"}),"."]}),"\n",(0,a.jsx)(t.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,a.jsxs)(t.p,{children:["In conclusion, the EntryPoint efficiently executes the bundled UserOperations and ensures fair compensation for the beneficiary by collecting fees. This is the flow of ",(0,a.jsx)(t.code,{children:"handleOp"}),". There is also ",(0,a.jsx)(t.code,{children:"handleAggregatorOp"}),". Note also the EntryPoint extends ",(0,a.jsx)(t.code,{children:"StakeManger"})," found in ",(0,a.jsx)(t.code,{children:"core/StakeManger.sol"})," which as mentioned is responsible for managing ",(0,a.jsx)(t.code,{children:"deposits"})," and stakes to ensure reimbursement for beneficiaries during the execution of handleOps and handleAggregatedOps functions. Deposits represent balances used to cover the costs of UserOperations, while stakes are values locked for a specified duration by paymasters, crucial for the reputation system. To learn more about the EIP proposal and its specifications, you can refer to the official document ",(0,a.jsx)(t.a,{href:"https://eips.ethereum.org/EIPS/eip-4337",children:"here"}),"."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},3456:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{src:t}=e;return(0,a.jsx)("img",{className:"rounded-lg w-full",src:t,alt:"cover"})}},2168:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{url:t}=e;return(0,a.jsx)("iframe",{src:t,height:"400",width:"300",style:{borderRadius:"8px",width:"100%",overflow:"hidden"}})}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>o});var a=n(6540);const s={},i=a.createContext(s);function r(e){const t=a.useContext(i);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),a.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a0834fcb.5ca99d5b.js b/assets/js/a0834fcb.5ca99d5b.js deleted file mode 100644 index 6404f7d..0000000 --- a/assets/js/a0834fcb.5ca99d5b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8390],{890:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>d,metadata:()=>h,toc:()=>u});var a=n(4848),s=n(8453),i=(n(6540),n(2168)),r=n(3456),o=n(9900),c=n(2345);const d={slug:"/ethereum/erc4337/entrypoint",title:"ERC4337 - Decoding Ethereum's EntryPoint",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["erc4337","account-abstraction","ethereum","entry-point"]},l=void 0,h={permalink:"/doc/blog/ethereum/erc4337/entrypoint",source:"@site/blog/erc4337/entry-point/2024-03-02-index.md",title:"ERC4337 - Decoding Ethereum's EntryPoint",description:"{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"basic",children:"Basic"}),"\n",(0,a.jsxs)(t.p,{children:["Before we go into the details of the EntryPoint, we need to understand the basic flow of how the EntryPoint works. The EntryPoint is a smart contract that is used to execute ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The ",(0,a.jsx)(t.code,{children:"UserOperation"})," is a struct that contains all the necessary information to execute a transaction. The EntryPoint is used to execute multiple UserOperations at once. This is done to save gas costs and to make the execution of transactions more efficient."]}),"\n",(0,a.jsx)(t.h3,{id:"useroperation",children:"UserOperation"}),"\n",(0,a.jsxs)(t.p,{children:["The primary data structure for user interaction within the Account Abstraction framework is encapsulated in ",(0,a.jsx)(t.code,{children:"interfaces/UserOperation.sol"}),". This structure is typically created by the Bundler and transmitted to the EntryPoint contract. The ",(0,a.jsx)(t.code,{children:"UserOperation"})," struct comprises the following fields:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"struct UserOperation {\r\n address sender;\r\n uint256 nonce;\r\n bytes initCode;\r\n bytes callData;\r\n uint256 callGasLimit;\r\n uint256 verificationGasLimit;\r\n uint256 preVerificationGas;\r\n uint256 maxFeePerGas;\r\n uint256 maxPriorityFeePerGas;\r\n bytes paymasterAndData;\r\n bytes signature;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["An example of a ",(0,a.jsx)(t.code,{children:"UserOperation"})," is provided below:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-typescript",children:"const emptyUserOp: UserOperation = {\r\n sender: AddressZero,\r\n callData: '0x',\r\n nonce: 0,\r\n preVerificationGas: 0,\r\n verificationGasLimit: 100000,\r\n callGasLimit: 0,\r\n maxFeePerGas: 0,\r\n maxPriorityFeePerGas: 0,\r\n signature: '0x'\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In contrast to the traditional approach of sending signed transactions to a mempool for validation, the initial step in ERC-4337 involves dispatching an operation in the form of a ",(0,a.jsx)(t.strong,{children:"UserOperation"}),". These operations are then forwarded to an alternative mempool. Users have the capability to dispatch multiple UserOperations concurrently through a Bundler smart contract, referred to as Bundler Transactions."]}),"\n",(0,a.jsx)(t.h3,{id:"entry-point-contract-on-ethereum",children:"Entry Point Contract on Ethereum"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.strong,{children:"EntryPoint"})," (EP) contract on Ethereum, found at ",(0,a.jsx)(t.a,{href:"https://etherscan.io/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",children:"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"}),", is crucial for handling ",(0,a.jsx)(t.code,{children:"bundlerTransactions"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["You can explore this contract using Solidity's IDE ",(0,a.jsx)(t.code,{children:"${SOLIDE_URL}/1/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789)"})]}),"\n",(0,a.jsxs)(t.p,{children:["As of writing this, it's contract version is ",(0,a.jsx)(t.code,{children:"0.6.0"})," and serves as the main hub for processing batches of ",(0,a.jsx)(t.code,{children:"UserOperations"}),". The contract offers two main methods: ",(0,a.jsx)(t.code,{children:"handleOps"})," and ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"}),". We'll focus on ",(0,a.jsx)(t.code,{children:"handleOps"})," for now, leaving ",(0,a.jsx)(t.code,{children:"handleAggregatedOps"})," for later discussion."]}),"\n",(0,a.jsx)(t.h2,{id:"-handleops",children:"\ud83d\udc49 handleOps"}),"\n",(0,a.jsxs)(t.p,{children:["The main flow of a using the EntryPoint typically comes from the ",(0,a.jsx)(t.code,{children:"Bundler"})," contracts which calls, the ",(0,a.jsx)(t.code,{children:"handleOps()"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function handleOps(UserOperation[] calldata ops, address payable beneficiary) public nonReentrant\n"})}),"\n",(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Non-Reentrant Modifier"}),": This modifier prevents reentrancy attacks, ensuring the security of the smart contract."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"UserOperation Array"}),": The ",(0,a.jsx)(t.code,{children:"ops"})," array consists of ",(0,a.jsx)(t.code,{children:"UserOperation"})," objects, stored in ",(0,a.jsx)(t.code,{children:"calldata"}),". These objects hold data passed to the contract's entry point."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Beneficiary Address"}),": The ",(0,a.jsx)(t.code,{children:"beneficiary"})," address is where gas refunds are sent after execution. Typically, this address corresponds to the bundler, but it can be set to any desired address."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 opslen = ops.length;\r\nUserOpInfo[] memory opInfos = new UserOpInfo[](opslen);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Before executing the UserOperations, the EntryPoint will validate each UserOperation. It'll create a ",(0,a.jsx)(t.code,{children:"UserOpInfo"})," array to store the information of each UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"for (uint256 i = 0; i < opslen; i++) {\r\n\tUserOpInfo memory opInfo = opInfos[i];\r\n\t(uint256 validationData, uint256 pmValidationData) = _validatePrepayment(i, ops[i], opInfo);\r\n\t_validateAccountAndPaymasterValidationData(i, validationData, pmValidationData, address(0));\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["In order to populate the opInfos from the Bundler, the function will undergo validation check in its loops. In order to save gas it'll be in the ",(0,a.jsx)(t.code,{children:"uncheck"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsxs)(t.p,{children:["After the validation of both the Account and Paymaster, the validation is check if see if they expire in ",(0,a.jsx)(t.code,{children:"_validateAccountAndPaymasterValidationData"}),". If the validation is successful, the EntryPoint will execute the UserOperations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-validateaccountandpaymastervalidationdata",children:"_validateAccountAndPaymasterValidationData"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 collected = 0;\r\nemit BeforeExecution();\r\n\r\nfor (uint256 i = 0; i < opslen; i++) {\r\n collected += _executeUserOp(i, ops[i], opInfos[i]);\r\n}\r\n\r\n_compensate(beneficiary, collected);\n"})}),"\n",(0,a.jsx)(t.p,{children:"With all validation complete it'll emits an event before execution begins. Then start iterating through each user operation, executing them and adding the gas fees consumed by each operation to the total collected amount. After all operations are executed, it compensates the specified beneficiary with the total collected gas fees, transferring them to the beneficiary's address."}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_executeuserop",children:"_executeUserOp"})]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#-_compensate",children:"_compensate"})]}),"\n",(0,a.jsx)(t.h2,{id:"\ufe0f-_validateprepayment",children:"\u2714\ufe0f _validatePrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validatePrepayment(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory outOpInfo)\r\n\tprivate returns (uint256 validationData, uint256 paymasterValidationData)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," function serves a pivotal role in upholding the integrity and safety of UserOperations within the account abstraction framework."]}),"\n",(0,a.jsx)(t.p,{children:"It takes in three parameters:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"opIndex"}),": The index of the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"userOp"}),": The UserOperation data structure containing essential information about the operation."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo"}),": A UserOpInfo structure used for storing operation-specific data during validation."]}),"\n"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = outOpInfo.mUserOp;\r\n_copyUserOpToMemory(userOp, mUserOp);\r\noutOpInfo.userOpHash = getUserOpHash(userOp);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Initially, the function tracks the remaining gas at the start of its execution. Utilizing the built-in Solidity function ",(0,a.jsx)(t.code,{children:"gasleft()"}),", it determines the amount of gas remaining within the current Ethereum transaction. ",(0,a.jsxs)(t.em,{children:["Throughout the call to the EntryPoint, ",(0,a.jsx)(t.code,{children:"gasleft"})," is employed to inform decisions based on the gas supplied by the Bundler."]})," Subsequently, it creates a copy the data from ",(0,a.jsx)(t.code,{children:"userOp"})," into memory for efficient processing. Following this, it calculates a hash of the UserOperation data using the ",(0,a.jsx)(t.code,{children:"getUserOpHash"})," function. This hash functions as a unique identifier for the operation, facilitating validation processes."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");\n'})}),"\n",(0,a.jsx)(t.p,{children:"This line of code ensures that certain numeric values within the UserOperation data, such as gas limits, do not exceed the maximum value representable by a 120-bit unsigned integer. This safeguard is implemented to mitigate the risk of overflow during subsequent calculations."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"uint256 gasUsedByValidateAccountPrepayment;\r\n(uint256 requiredPreFund) = _getRequiredPrefund(mUserOp);\r\n(gasUsedByValidateAccountPrepayment, validationData) = _validateAccountPrepayment(opIndex, userOp, outOpInfo, requiredPreFund);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The function continues by calculating the gas needed to pre-fund the operation. This calculation is based on the UserOperation data and specific conditions defined within the ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"})," function. Furthermore, the function conducts validation checks using ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),". These checks ensure that the account ",(0,a.jsx)(t.em,{children:"(Smart Contract Wallet)"})," , possesses adequate funds and allowances to cover the operation's gas costs."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validateaccountprepayment",children:"_validateAccountPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (mUserOp.paymaster != address(0)) {\r\n\t(context, paymasterValidationData) = _validatePaymasterPrepayment(opIndex, userOp, outOpInfo, requiredPreFund, gasUsedByValidateAccountPrepayment);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This next stage is optional, contingent upon the bundler's inclusion of a paymaster for the UserOperation. ",(0,a.jsx)(t.em,{children:"A paymaster, integral component in Account Abstraction as it enables users to settle transaction feees such as utilizing ERC-20 tokens rather than native tokens like ETH. Acting as an intermediary, the Paymaster gathers ERC-20 tokens from users and remits ETH to the blockchain for transaction facilitation."})," Therefore, this aspect is a crucial addition to the EntryPoint, permitting the Bundler to cover the UserOperation costs using ERC-20 tokens instead of native tokens such as ETH."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 gasUsed = preGas - gasleft();\r\n\r\nif (userOp.verificationGasLimit < gasUsed) {\r\nrevert FailedOp(opIndex, "AA40 over verificationGasLimit");\r\n}\r\noutOpInfo.prefund = requiredPreFund;\r\noutOpInfo.contextOffset = getOffsetOfMemoryBytes(context);\r\noutOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;\n'})}),"\n",(0,a.jsxs)(t.p,{children:["After completing the necessary gas calculations and validations, the function ensures that the gas utilized during validation does not surpass the specified verification gas limit. Upon success, it finalizes the pre-funding details within the ",(0,a.jsx)(t.code,{children:"outOpInfo"})," structure, encompassing the pre-fund amount, memory context offset, and pre-operation gas usage."]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.prefund"})," is set to the ",(0,a.jsx)(t.code,{children:"requiredPreFund"})," value, which represents the maximum gas fee deducted from the deposit on EP."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.contextOffset"})," is designated as the offset of the context object in memory. Note that the context object is returned by the ",(0,a.jsx)(t.code,{children:"Paymaster.validatePaymasterUserOp"})," call. By storing only the memory offset of the context object, we alleviate the need to pass around the entire context object while invoking internal methods."]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"outOpInfo.preOpGas"})," is determined as the sum of the total gas used thus far and the ",(0,a.jsx)(t.code,{children:"userOp.preVerificationGas"}),"."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["In summary, ",(0,a.jsx)(t.code,{children:"_validatePrepayment"})," assumes a role of guaranteeing the validity and safety of UserOperations within the account abstraction framework. It encompasses crucial tasks such as gas tracking, hashing, validation, and pre-funding calculations, ensuring the seamless and secure execution of operations."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validateaccountprepayment",children:"_validateAccountPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"_createSenderIfNeeded(opIndex, opInfo, op.initCode);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This internal method is crucial for validating the operation with a Smart Contract Wallet (SCW). Initially, it calls upon a Factory contract to create the account if required, utilizing ",(0,a.jsx)(t.code,{children:"_createSenderIfNeeded"}),". The Wallet contract generated by this factory must adhere to ",(0,a.jsx)(t.code,{children:"interfaces/IAccount.sol"}),", which includes the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function. This function is essential for validating the UserOp's signature, enabling the EntryPoint to execute operations on a Wallet account."]}),"\n",(0,a.jsxs)(t.p,{children:["Once the Smart Contract Wallet is deemed valid for further validation, the method proceeds to perform calculations on the gas funds and validate the ",(0,a.jsx)(t.code,{children:"validateUserOp"})," function on the SCW if and only if ",(0,a.jsx)(t.code,{children:"paymaster == address(0)"}),". This condition signifies that the SCW, either passed or generated, will be responsible for covering the current UserOperation execution(s)."]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"Important stage in handleOps"}),"\r\nAs this point, the EntryPoint call stack should ",(0,a.jsx)(t.code,{children:"handleOps.validatePrePayment._validateAccountPrepayment"}),", where the EntryPoint is validating that the SCW has enough gas to cover the UserOperation."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try IAccount(sender).validateUserOp{gas : mUserOp.verificationGasLimit}(op, opInfo.userOpHash, missingAccountFunds)\n"})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["There is also the introducation reverting the entire transaction if validations fails from the SCW or the call runs out of gas. Mainly the ",(0,a.jsx)(t.code,{children:"FailedOp"})," will revert the transaction."]})}),"\n",(0,a.jsxs)(t.p,{children:["Upon successful validation, both ",(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," and ",(0,a.jsx)(t.code,{children:"validationData"})," provided by the SCW through its ",(0,a.jsx)(t.code,{children:"IAccount"})," interface are captured. It is crucial that the validation logic is tailored and executed according to each user's preferences and requirements."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsx)(t.h3,{id:"_validatepaymasterprepayment",children:"_validatePaymasterPrepayment"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'uint256 preGas = gasleft();\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\naddress paymaster = mUserOp.paymaster;\r\nDepositInfo storage paymasterInfo = deposits[paymaster];\r\nuint256 deposit = paymasterInfo.deposit;\r\nif (deposit < requiredPreFund) {\r\n revert FailedOp(opIndex, "AA31 paymaster deposit too low");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Similarly to the ",(0,a.jsx)(t.code,{children:"_validateAccountPrepayment"}),", this time, it'll check the paymaster's deposit balance in EP. If there is enough despot compared to the provided , it'll deduct the that the the requiredPreFund from the Paymaster's deposit,"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'MemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 verificationGasLimit = mUserOp.verificationGasLimit;\r\nrequire(verificationGasLimit > gasUsedByValidateAccountPrepayment, "AA41 too little verificationGas");\r\nuint256 gas = verificationGasLimit - gasUsedByValidateAccountPrepayment;\n'})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"gasUsedByValidateAccountPrepayment"})," calculated by the Account validation, is used to calculate the gas required to pay back the bundler. This is done via ",(0,a.jsx)(t.code,{children:"_getRequiredPrefund"}),". Since the EntryPoint is executing the UserOperations, this means that EntryPoint must ensure it has enough gas to execute those UserOperations and in order for the Bundler to obtain the gas, depends on whether a Paymaster is setup or the Smart Contract Wallet provided."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"paymasterInfo.deposit = deposit - requiredPreFund\n"})}),"\n",(0,a.jsxs)(t.p,{children:["After deducting the deposit as mention call the validationOp's ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"})," for paymaster of ",(0,a.jsx)(t.code,{children:"interfaces/IPaymaster.sol"})," and with the \xa0",(0,a.jsx)(t.code,{children:"userOp.verificationGasLimit"}),"\xa0as gas limit and return the validation Data."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"IPaymaster(paymaster).validatePaymasterUserOp{gas: gas}(op, opInfo.userOpHash, requiredPreFund) returns (bytes memory _context, uint256 _validationData) \n"})}),"\n",(0,a.jsxs)(t.p,{children:["This will return ",(0,a.jsx)(t.em,{children:"context object"})," and ",(0,a.jsx)(t.code,{children:"validationData"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#%EF%B8%8F-_validateprepayment",children:"_validatePrepayment"})]}),"\n",(0,a.jsx)(t.h2,{id:"\ufe0f-validateaccountandpaymastervalidationdata",children:"\u2714\ufe0f validateAccountAndPaymasterValidationData"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _validateAccountAndPaymasterValidationData(uint256 opIndex, uint256 validationData, uint256 paymasterValidationData,\r\n address expectedAggregator)\n"})}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.code,{children:"validateAccountAndPaymasterValidationData"})," serves to validate the validation data from both the Smart Contract Wallet (SCW) and Paymaster. It verifies if the validation data has expired and reverts the transaction if it has. Notably, in the Ethereum EntryPoint, the ",(0,a.jsx)(t.code,{children:"address(0)"})," represents the ",(0,a.jsx)(t.code,{children:"expectedAggregator"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Before unpacking the validationData, An example of validation data is as follows as taken by ",(0,a.jsx)(t.code,{children:"account-abstraction/ethereum/contracts/TokenPaymaster.sol"}),". ",(0,a.jsx)(t.em,{children:"Note this is just an example, other Paymaster's or SCW validation will have different validation data depending on it implementation."})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"validationResult = _packValidationData(\r\n\tfalse,\r\n\tuint48(cachedPriceTimestamp + tokenPaymasterConfig.priceMaxAge),\r\n\t0\r\n);\n"})}),"\n",(0,a.jsx)(t.p,{children:"The validationData comprises three components, which are essential for the EntryPoint to validate the UserOperation,"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Aggregator: This value signifies the success of the aggregator. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator. For instance, if ",(0,a.jsx)(t.code,{children:"false"})," is provided, it results in the value ",(0,a.jsx)(t.code,{children:"0"}),", indicating success."]}),"\n",(0,a.jsx)(t.li,{children:"ValidUntil: This represents the start time when the signature is valid."}),"\n",(0,a.jsx)(t.li,{children:"ValidAfter: This denotes the end time when the signature is valid."}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["These components collectively determine whether signature verification was successful. The primary implementation of parsing the validationData is outlined in ",(0,a.jsx)(t.code,{children:"Helper.sol"})," within the ",(0,a.jsx)(t.code,{children:"_parseValidationData"})," function. In essence, this method extracts the aggregator value (an ",(0,a.jsx)(t.code,{children:"address"}),"), the validUntil timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),"), and the validAfter timestamp (a ",(0,a.jsx)(t.code,{children:"uint48"}),") from the validationData. If the validUntil value is 0, as observed in the example provided, it signifies that the signature is valid until the maximum value of ",(0,a.jsx)(t.code,{children:"uint48"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"Since both validationData and paymasterValidationData undergo validation in a similar manner, we'll focus on the paymasterValidationData. The validation process involves comparing these values with the current block timestamp in the EntryPoint to ascertain their validity."}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'address pmAggregator;\r\n(pmAggregator, outOfTimeRange) = _getValidationData(paymasterValidationData);\r\nif (pmAggregator != address(0)) {\r\n\trevert FailedOp(opIndex, "AA34 signature error");\r\n}\r\nif (outOfTimeRange) {\r\n\trevert FailedOp(opIndex, "AA32 paymaster expired or not due");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Hence if we go back to the EntryPoint where it'll parse the above ",(0,a.jsx)(t.code,{children:"validationResult"})," as ",(0,a.jsx)(t.code,{children:"paymasterValidationData"})," we see it extractsthe ",(0,a.jsx)(t.code,{children:"pmAggregator"})," variable represents the aggregator status obtained from the paymasterValidationData. A value of ",(0,a.jsx)(t.code,{children:"0"})," indicates a successful aggregator, while ",(0,a.jsx)(t.code,{children:"1"})," implies an expired aggregator. With this, if ",(0,a.jsx)(t.code,{children:"pmAggregator"})," is assigned the value of ",(0,a.jsx)(t.code,{children:"address(0)"}),", it signifies that the aggregator is successful as it has the value of ",(0,a.jsx)(t.code,{children:"0"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Furthermore, validation is conducted by comparing the current block timestamp with the validUntil and validAfter timestamps obtained from the validation data. The ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," variable is set based on whether the current timestamp exceeds the validUntil timestamp or falls before the validAfter timestamp. If ",(0,a.jsx)(t.code,{children:"outOfTimeRange"})," is ",(0,a.jsx)(t.code,{children:"true"}),", it indicates that the paymaster has expired or the operation is not yet due."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter;\n"})}),"\n",(0,a.jsx)(t.p,{children:'In summary, the code snippet checks the status of the aggregator and verifies the validity of the paymaster based on timestamps, ensuring that the operation is executed within the designated time range. If any discrepancy is detected, the function reverts the transaction with an appropriate error message, such as "signature error" or "paymaster expired or not due."'}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h3,{id:"numbermarker",children:"numberMarker()"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"//place the NUMBER opcode in the code.\r\n// this is used as a marker during simulation, as this OP is completely banned from the simulated code of the\r\n// account and paymaster.\r\nfunction numberMarker() internal view {\r\n assembly {mstore(0, number())}\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This function is mainly useful for the method ",(0,a.jsx)(t.code,{children:"simulateValidation"}),", for tracing and checkpoints throughout the code. For our purpose, we don't need to really worry about this."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},2345:(e,t,n)=>{n.d(t,{Ay:()=>r});var a=n(4848),s=n(8453);function i(e){const t={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"\ufe0f-_executeuserop",children:"\ud83d\udee0\ufe0f _executeUserOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _executeUserOp(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory opInfo) \r\n private returns (uint256 collected)\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code begins by retrieving the context from memory. The context is stored as a byte array and contains essential information needed for the ",(0,a.jsx)(t.code,{children:"Paymaster.postOp"})," function."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"try this.innerHandleOp(userOp.callData, opInfo, context) returns (\r\n uint256 _actualGasCost\r\n) {\r\n collected = _actualGasCost;\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The code then attempts to execute the UserOperation by invoking the ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," function. This function, implemented by the Paymaster, takes ",(0,a.jsx)(t.code,{children:"userOp.callData"}),", ",(0,a.jsx)(t.code,{children:"opInfo"}),", and ",(0,a.jsx)(t.code,{children:"context"})," as parameters. Upon invocation, ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," returns the actual gas cost incurred by the operation, which is subsequently added to the ",(0,a.jsx)(t.code,{children:"collected"})," variable."]}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#innerhandleop",children:"innerHandleOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"innerhandleop",children:"innerHandleOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function innerHandleOp(\r\n bytes memory callData,\r\n UserOpInfo memory opInfo,\r\n bytes calldata context\r\n) external returns (uint256 actualGasCost)\n"})}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"innerHandleOp"})," method is invoked to execute the ",(0,a.jsx)(t.code,{children:"UserOperation"})," calldata on the wallet contract. Leveraging the ",(0,a.jsx)(t.code,{children:"Exec"})," solidity library, available in ",(0,a.jsx)(t.code,{children:"util/Exec.sol"}),", developers gain access to a range of utility functions designed for diverse contract calls. These include regular ",(0,a.jsx)(t.em,{children:"call"}),", ",(0,a.jsx)(t.em,{children:"staticcall"}),", and ",(0,a.jsx)(t.em,{children:"delegatecall"})," functionalities, along with features for retrieving return data and reverting with explicit byte arrays. Such capabilities empower developers to interact flexibly and efficiently with other contracts directly within Solidity contracts, seamlessly managing value transfers and data retrieval. In the following code snippet, ",(0,a.jsx)(t.code,{children:"Exec.call"})," is utilized\u2014a low-level call function\u2014utilizing the calldata provided by ",(0,a.jsx)(t.code,{children:"userOp.callData"}),"."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"if (callData.length > 0) {\r\n bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);\r\n if (!success) {\r\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\r\n if (result.length > 0) {\r\n emit UserOperationRevertReason(opInfo.userOpHash, mUserOp.sender, mUserOp.nonce, result);\r\n }\r\n mode = IPaymaster.PostOpMode.opReverted;\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"unchecked {\r\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\r\n //note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp)\r\n return _handlePostOp(0, mode, opInfo, context, actualGas);\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["Go to implementation information for ",(0,a.jsx)(t.a,{href:"#_handlepostop",children:"_handlePostOp"})]}),"\n",(0,a.jsx)(t.h3,{id:"_handlepostop",children:"_handlePostOp"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"function _handlePostOp(uint256 opIndex, IPaymaster.PostOpMode mode, UserOpInfo memory opInfo, bytes memory context, \r\n uint256 actualGas) private returns (uint256 actualGasCost) \n"})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:"address refundAddress;\r\nMemoryUserOp memory mUserOp = opInfo.mUserOp;\r\nuint256 gasPrice = getUserOpGasPrice(mUserOp);\r\n\r\naddress paymaster = mUserOp.paymaster;\r\nif (paymaster == address(0)) {\r\n refundAddress = mUserOp.sender;\r\n} else {\r\n refundAddress = paymaster;\r\n // ...\r\n}\n"})}),"\n",(0,a.jsxs)(t.p,{children:["When a paymaster is specified and its validation results is a non-empty context, the surplus amount is reimbursed to the account or paymaster, depending on its involvement in the transaction request. As mentioned, the following code executes the ",(0,a.jsx)(t.code,{children:"IPaymaster"}),"'s ",(0,a.jsx)(t.code,{children:"postOp"})," function, which is another essential method similar to ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp"}),"."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["The ",(0,a.jsx)(t.code,{children:"postOp()"})," function acts as a post-execution hook after completing a user operation. It manages tasks to be executed upon successful validation of the user operation, such as handling custom token payments for transaction fees. For example, if a user chooses to pay with an ERC-20 token, the entry point invokes ",(0,a.jsx)(t.code,{children:"postOp()"})," after executing the operation and provides information about gas consumption. Importantly, access to ",(0,a.jsx)(t.code,{children:"postOp()"})," is contingent upon the validation context generated by ",(0,a.jsx)(t.code,{children:"validatePaymasterUserOp()"})," not being null. This mechanism simplifies the process of managing token payments and facilitates smooth transaction processing on the blockchain."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'if (context.length > 0) {\r\n actualGasCost = actualGas * gasPrice;\r\n if (mode != IPaymaster.PostOpMode.postOpReverted) {\r\n IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost);\r\n } else {\r\n // solhint-disable-next-line no-empty-blocks\r\n try IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost) {}\r\n catch Error(string memory reason) {\r\n revert FailedOp(opIndex, string.concat("AA50 postOp reverted: ", reason));\r\n }\r\n catch {\r\n revert FailedOp(opIndex, "AA50 postOp revert");\r\n }\r\n }\r\n}\n'})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'actualGas += preGas - gasleft();\r\nactualGasCost = actualGas * gasPrice;\r\nif (opInfo.prefund < actualGasCost) {\r\n revert FailedOp(opIndex, "AA51 prefund below actualGasCost");\r\n}\r\nuint256 refund = opInfo.prefund - actualGasCost;\r\n_incrementDeposit(refundAddress, refund);\r\nbool success = mode == IPaymaster.PostOpMode.opSucceeded;\r\nemit UserOperationEvent(opInfo.userOpHash, mUserOp.sender, mUserOp.paymaster, mUserOp.nonce, success, actualGasCost, actualGas);\n'})}),"\n",(0,a.jsx)(t.p,{children:"After determining the refund address and ensuring that the paymaster context isn't empty, the code proceeds to calculate the actual gas usage and its associated cost during the execution of a smart contract operation. It then verifies whether the prefunded amount is adequate to cover the gas cost. If not, the transaction is reverted. Any excess prefunded amount is calculated as a refund and subsequently added to the deposit of the specified address. Finally, the success status of the operation is determined based on the paymaster's mode setting."}),"\n",(0,a.jsx)(t.p,{children:"Additionally:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"_incrementDeposit"})," function in the ",(0,a.jsx)(t.code,{children:"StakeManager"})," contract is invoked to increase the paymaster's deposit by the actual gas cost."]}),"\n",(0,a.jsxs)(t.li,{children:["The ",(0,a.jsx)(t.code,{children:"actualGasCost = actualGas * gasPrice"})," calculation determines the actual gas cost of the operation, which is stored as the value of ",(0,a.jsx)(t.code,{children:"collected"})," in the ",(0,a.jsx)(t.code,{children:"handleOps"})," function."]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["Go back to ",(0,a.jsx)(t.a,{href:"#-handleops",children:"handleOps"})]}),"\n",(0,a.jsx)(t.h2,{id:"-_compensate",children:"\ud83d\udcb5 _compensate"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-solidity",children:'/**\r\n * compensate the caller\'s beneficiary address with the collected fees of all UserOperations.\r\n * @param beneficiary the address to receive the fees\r\n * @param amount amount to transfer.\r\n */\r\nfunction _compensate(address payable beneficiary, uint256 amount) internal {\r\n require(beneficiary != address(0), "AA90 invalid beneficiary");\r\n (bool success,) = beneficiary.call{value : amount}("");\r\n require(success, "AA91 failed send to beneficiary");\r\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["The final step is to compensate the beneficiary with the collected fees. The collected fees are transferred to the beneficiary address. The beneficiary address can be any address where the bundler wants to receive the refund as provided in the ",(0,a.jsx)(t.code,{children:"handleOps"}),"."]}),"\n",(0,a.jsx)(t.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,a.jsxs)(t.p,{children:["In conclusion, the EntryPoint efficiently executes the bundled UserOperations and ensures fair compensation for the beneficiary by collecting fees. This is the flow of ",(0,a.jsx)(t.code,{children:"handleOp"}),". There is also ",(0,a.jsx)(t.code,{children:"handleAggregatorOp"}),". Note also the EntryPoint extends ",(0,a.jsx)(t.code,{children:"StakeManger"})," found in ",(0,a.jsx)(t.code,{children:"core/StakeManger.sol"})," which as mentioned is responsible for managing ",(0,a.jsx)(t.code,{children:"deposits"})," and stakes to ensure reimbursement for beneficiaries during the execution of handleOps and handleAggregatedOps functions. Deposits represent balances used to cover the costs of UserOperations, while stakes are values locked for a specified duration by paymasters, crucial for the reputation system. To learn more about the EIP proposal and its specifications, you can refer to the official document ",(0,a.jsx)(t.a,{href:"https://eips.ethereum.org/EIPS/eip-4337",children:"here"}),"."]})]})}function r(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(i,{...e})}):i(e)}},3456:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{src:t}=e;return(0,a.jsx)("img",{className:"rounded-lg w-full",src:t,alt:"cover"})}},2168:(e,t,n)=>{n.d(t,{A:()=>s});var a=n(4848);const s=e=>{let{url:t}=e;return(0,a.jsx)("iframe",{src:t,height:"400",width:"300",style:{borderRadius:"8px",width:"100%",overflow:"hidden"}})}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>o});var a=n(6540);const s={},i=a.createContext(s);function r(e){const t=a.useContext(i);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),a.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bd03c5f3.84d014b5.js b/assets/js/bd03c5f3.84d014b5.js new file mode 100644 index 0000000..213f553 --- /dev/null +++ b/assets/js/bd03c5f3.84d014b5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8539],{4565:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>m});var r=o(4848),n=o(8453);const a={slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},s="Coming Soon",c={permalink:"/doc/blog/ethereum/erc4337/paymaster",source:"@site/blog/erc4337/paymaster/index.md",title:"ERC4337 - Paymaster",description:"",date:"2024-03-02T08:47:20.000Z",formattedDate:"March 2, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:0,hasTruncateMarker:!1,authors:[{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,nextItem:{title:"ERC4337 - Decoding Ethereum's EntryPoint",permalink:"/doc/blog/ethereum/erc4337/entrypoint"}},i={authorsImageUrls:[void 0]},m=[];function l(e){return(0,r.jsx)(r.Fragment,{})}function u(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l()}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>c});var r=o(6540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bd03c5f3.f94d5841.js b/assets/js/bd03c5f3.f94d5841.js deleted file mode 100644 index ce2a246..0000000 --- a/assets/js/bd03c5f3.f94d5841.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8539],{4565:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>m});var r=o(4848),n=o(8453);const a={slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},s="Coming Soon",c={permalink:"/doc/blog/ethereum/erc4337/paymaster",source:"@site/blog/erc4337/paymaster/index.md",title:"ERC4337 - Paymaster",description:"",date:"2024-02-27T04:29:23.846Z",formattedDate:"February 27, 2024",tags:[{label:"open-source",permalink:"/doc/blog/tags/open-source"},{label:"smart-contract",permalink:"/doc/blog/tags/smart-contract"},{label:"development-tool",permalink:"/doc/blog/tags/development-tool"}],readingTime:0,hasTruncateMarker:!1,authors:[{name:"P",title:"Software Engineer @ Solide",url:"https://github.com/solide-project",imageURL:"https://avatars.githubusercontent.com/u/154510112?s=200&v=4",key:"p"}],frontMatter:{slug:"/ethereum/erc4337/paymaster",title:"ERC4337 - Paymaster",image:"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png",authors:["p"],tags:["open-source","smart-contract","development-tool"]},unlisted:!1,prevItem:{title:"ERC4337 - Decoding Ethereum's EntryPoint",permalink:"/doc/blog/ethereum/erc4337/entrypoint"},nextItem:{title:"Welcome",permalink:"/doc/blog/welcome"}},l={authorsImageUrls:[void 0]},m=[];function i(e){return(0,r.jsx)(r.Fragment,{})}function u(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(i,{...e})}):i()}},8453:(e,t,o)=>{o.d(t,{R:()=>s,x:()=>c});var r=o(6540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e417d728.295810bd.js b/assets/js/e417d728.295810bd.js new file mode 100644 index 0000000..51a4a07 --- /dev/null +++ b/assets/js/e417d728.295810bd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[2361],{2958:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/ethereum/erc4337/paymaster","metadata":{"permalink":"/doc/blog/ethereum/erc4337/paymaster","source":"@site/blog/erc4337/paymaster/index.md","title":"ERC4337 - Paymaster","description":"","date":"2024-03-02T08:47:20.000Z","formattedDate":"March 2, 2024","tags":[{"label":"open-source","permalink":"/doc/blog/tags/open-source"},{"label":"smart-contract","permalink":"/doc/blog/tags/smart-contract"},{"label":"development-tool","permalink":"/doc/blog/tags/development-tool"}],"readingTime":0,"hasTruncateMarker":false,"authors":[{"name":"P","title":"Software Engineer @ Solide","url":"https://github.com/solide-project","imageURL":"https://avatars.githubusercontent.com/u/154510112?s=200&v=4","key":"p"}],"frontMatter":{"slug":"/ethereum/erc4337/paymaster","title":"ERC4337 - Paymaster","image":"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png","authors":["p"],"tags":["open-source","smart-contract","development-tool"]},"unlisted":false,"nextItem":{"title":"ERC4337 - Decoding Ethereum\'s EntryPoint","permalink":"/doc/blog/ethereum/erc4337/entrypoint"}},"content":""},{"id":"/ethereum/erc4337/entrypoint","metadata":{"permalink":"/doc/blog/ethereum/erc4337/entrypoint","source":"@site/blog/erc4337/entry-point/2024-03-02-index.md","title":"ERC4337 - Decoding Ethereum\'s EntryPoint","description":"\\r\\n\\r\\n\\r\\n\\r\\n"},{"id":"welcome","metadata":{"permalink":"/doc/blog/welcome","source":"@site/blog/2024-02-21/index.md","title":"Welcome","description":"Welcome to Solide","date":"2024-02-21T00:00:00.000Z","formattedDate":"February 21, 2024","tags":[{"label":"open-source","permalink":"/doc/blog/tags/open-source"},{"label":"smart-contract","permalink":"/doc/blog/tags/smart-contract"},{"label":"development-tool","permalink":"/doc/blog/tags/development-tool"}],"readingTime":0.01,"hasTruncateMarker":false,"authors":[{"name":"A","title":"Software Engineer @ Solide","url":"https://github.com/solide-project","imageURL":"https://avatars.githubusercontent.com/u/154510112?s=200&v=4","key":"a"},{"name":"P","title":"Software Engineer @ Solide","url":"https://github.com/solide-project","imageURL":"https://avatars.githubusercontent.com/u/154510112?s=200&v=4","key":"p"}],"frontMatter":{"slug":"welcome","title":"Welcome","authors":["a","p"],"tags":["open-source","smart-contract","development-tool"]},"unlisted":false,"prevItem":{"title":"ERC4337 - Decoding Ethereum\'s EntryPoint","permalink":"/doc/blog/ethereum/erc4337/entrypoint"}},"content":"Welcome to Solide"}]}')}}]); \ No newline at end of file diff --git a/assets/js/e417d728.9842658a.js b/assets/js/e417d728.9842658a.js deleted file mode 100644 index 7ae1cfd..0000000 --- a/assets/js/e417d728.9842658a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[2361],{2958:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/ethereum/erc4337/entrypoint","metadata":{"permalink":"/doc/blog/ethereum/erc4337/entrypoint","source":"@site/blog/erc4337/entry-point/2024-03-02-index.md","title":"ERC4337 - Decoding Ethereum\'s EntryPoint","description":"\\r\\n\\r\\n\\r\\n\\r\\n"},{"id":"/ethereum/erc4337/paymaster","metadata":{"permalink":"/doc/blog/ethereum/erc4337/paymaster","source":"@site/blog/erc4337/paymaster/index.md","title":"ERC4337 - Paymaster","description":"","date":"2024-02-27T04:29:23.846Z","formattedDate":"February 27, 2024","tags":[{"label":"open-source","permalink":"/doc/blog/tags/open-source"},{"label":"smart-contract","permalink":"/doc/blog/tags/smart-contract"},{"label":"development-tool","permalink":"/doc/blog/tags/development-tool"}],"readingTime":0,"hasTruncateMarker":false,"authors":[{"name":"P","title":"Software Engineer @ Solide","url":"https://github.com/solide-project","imageURL":"https://avatars.githubusercontent.com/u/154510112?s=200&v=4","key":"p"}],"frontMatter":{"slug":"/ethereum/erc4337/paymaster","title":"ERC4337 - Paymaster","image":"https://raw.githubusercontent.com/solide-project/docs/master/static/img/blog/ethereum-entry-point.png","authors":["p"],"tags":["open-source","smart-contract","development-tool"]},"unlisted":false,"prevItem":{"title":"ERC4337 - Decoding Ethereum\'s EntryPoint","permalink":"/doc/blog/ethereum/erc4337/entrypoint"},"nextItem":{"title":"Welcome","permalink":"/doc/blog/welcome"}},"content":""},{"id":"welcome","metadata":{"permalink":"/doc/blog/welcome","source":"@site/blog/2024-02-21/index.md","title":"Welcome","description":"Welcome to Solide","date":"2024-02-21T00:00:00.000Z","formattedDate":"February 21, 2024","tags":[{"label":"open-source","permalink":"/doc/blog/tags/open-source"},{"label":"smart-contract","permalink":"/doc/blog/tags/smart-contract"},{"label":"development-tool","permalink":"/doc/blog/tags/development-tool"}],"readingTime":0.01,"hasTruncateMarker":false,"authors":[{"name":"A","title":"Software Engineer @ Solide","url":"https://github.com/solide-project","imageURL":"https://avatars.githubusercontent.com/u/154510112?s=200&v=4","key":"a"},{"name":"P","title":"Software Engineer @ Solide","url":"https://github.com/solide-project","imageURL":"https://avatars.githubusercontent.com/u/154510112?s=200&v=4","key":"p"}],"frontMatter":{"slug":"welcome","title":"Welcome","authors":["a","p"],"tags":["open-source","smart-contract","development-tool"]},"unlisted":false,"prevItem":{"title":"ERC4337 - Paymaster","permalink":"/doc/blog/ethereum/erc4337/paymaster"}},"content":"Welcome to Solide"}]}')}}]); \ No newline at end of file diff --git a/assets/js/main.8ce7cd54.js b/assets/js/main.b38f7fa4.js similarity index 99% rename from assets/js/main.8ce7cd54.js rename to assets/js/main.b38f7fa4.js index 710f7c0..f1f7ec2 100644 --- a/assets/js/main.8ce7cd54.js +++ b/assets/js/main.b38f7fa4.js @@ -1,2 +1,2 @@ -/*! For license information please see main.8ce7cd54.js.LICENSE.txt */ -(self.webpackChunksolide_docs=self.webpackChunksolide_docs||[]).push([[8792],{8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});n(6540);var r=n(3259),o=n.n(r),a=n(4054);const i={"01a85c17":[()=>Promise.all([n.e(1869),n.e(8209)]).then(n.bind(n,9158)),"@theme/BlogTagsListPage",9158],"0e384e19":[()=>n.e(3976).then(n.bind(n,1512)),"@site/docs/intro.md",1512],"12b59fe5":[()=>n.e(8470).then(n.t.bind(n,4829,19)),"~blog/default/doc-blog-tags-tags-5cd.json",4829],"14e6b30a":[()=>n.e(8649).then(n.bind(n,8775)),"@site/blog/erc4337/paymaster/index.md?truncated=true",8775],17896441:[()=>Promise.all([n.e(1869),n.e(2125),n.e(8401)]).then(n.bind(n,5022)),"@theme/DocItem",5022],"1df93b7f":[()=>n.e(4583).then(n.bind(n,6866)),"@site/src/pages/index.tsx",6866],"1e4f1eb0":[()=>n.e(8719).then(n.bind(n,5659)),"@site/docs/solide-ide/aspect-ide.md",5659],"1f391b9e":[()=>Promise.all([n.e(1869),n.e(2125),n.e(6061)]).then(n.bind(n,7973)),"@theme/MDXPage",7973],"2525e643":[()=>n.e(4269).then(n.bind(n,958)),"@site/blog/2024-02-21/index.md",958],"307c3b04":[()=>n.e(6719).then(n.bind(n,1396)),"@site/docs/supported-chains.md",1396],"393be207":[()=>n.e(4134).then(n.bind(n,6602)),"@site/src/pages/markdown-page.md",6602],"5bc8f176":[()=>n.e(9107).then(n.t.bind(n,8292,19)),"~blog/default/doc-blog-tags-account-abstraction-973-list.json",8292],"5e95c892":[()=>n.e(9647).then(n.bind(n,7121)),"@theme/DocsRoot",7121],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,4784)),"@generated/docusaurus.config",4784],"60a998dd":[()=>n.e(5716).then(n.t.bind(n,1451,19)),"~blog/default/doc-blog-tags-ethereum-072-list.json",1451],"61eac78a":[()=>n.e(6613).then(n.bind(n,7138)),"@site/blog/2024-02-21/index.md?truncated=true",7138],"6875c492":[()=>Promise.all([n.e(1869),n.e(2125),n.e(8747),n.e(4813)]).then(n.bind(n,3069)),"@theme/BlogTagsPostsPage",3069],"72b85e3f":[()=>n.e(667).then(n.t.bind(n,4498,19)),"~blog/default/doc-blog-tags-smart-contract-817.json",4498],"74ce7958":[()=>n.e(2905).then(n.bind(n,5838)),"@site/blog/erc4337/entry-point/2024-03-02-index.md?truncated=true",5838],"814f3328":[()=>n.e(7472).then(n.t.bind(n,5513,19)),"~blog/default/blog-post-list-prop-default.json",5513],"8b2a7939":[()=>n.e(8586).then(n.bind(n,2915)),"@site/docs/solide-ide/load-contract-source.md",2915],"935f2afb":[()=>n.e(8581).then(n.t.bind(n,5610,19)),"~docs/default/version-current-metadata-prop-751.json",5610],"983d6e9e":[()=>n.e(8528).then(n.t.bind(n,1557,19)),"~blog/default/doc-blog-tags-account-abstraction-973.json",1557],"9b9152a4":[()=>n.e(7286).then(n.t.bind(n,7887,19)),"~blog/default/doc-blog-tags-erc-4337-c43-list.json",7887],"9e4087bc":[()=>n.e(2711).then(n.bind(n,9331)),"@theme/BlogArchivePage",9331],a0834fcb:[()=>n.e(8390).then(n.bind(n,890)),"@site/blog/erc4337/entry-point/2024-03-02-index.md",890],a6aa9e1f:[()=>Promise.all([n.e(1869),n.e(2125),n.e(8747),n.e(7643)]).then(n.bind(n,7785)),"@theme/BlogListPage",7785],a7bd4aaa:[()=>n.e(7098).then(n.bind(n,4532)),"@theme/DocVersionRoot",4532],a7c74703:[()=>n.e(9369).then(n.t.bind(n,5892,19)),"~blog/default/doc-blog-tags-ethereum-072.json",5892],a94703ab:[()=>Promise.all([n.e(1869),n.e(9048)]).then(n.bind(n,2559)),"@theme/DocRoot",2559],a9b62f5b:[()=>n.e(2396).then(n.t.bind(n,4776,19)),"~blog/default/doc-blog-tags-erc-4337-c43.json",4776],b1abda8a:[()=>n.e(2961).then(n.bind(n,658)),"@site/docs/solide-dapp/manage-docs-versions.md",658],b6a293f9:[()=>n.e(5293).then(n.t.bind(n,1966,19)),"C:\\Users\\Peter\\Documents\\app\\solide\\docs\\.docusaurus\\docusaurus-plugin-content-docs\\default\\plugin-route-context-module-100.json",1966],b9b1355c:[()=>n.e(3751).then(n.t.bind(n,5642,19)),"~blog/default/doc-blog-tags-entry-point-f13-list.json",5642],bd03c5f3:[()=>n.e(8539).then(n.bind(n,4565)),"@site/blog/erc4337/paymaster/index.md",4565],bd950408:[()=>n.e(4783).then(n.t.bind(n,8157,19)),"~blog/default/doc-blog-tags-development-tool-4eb.json",8157],c0f6e2ef:[()=>n.e(1830).then(n.bind(n,9040)),"@site/docs/solide-ide/load-github-source.md",9040],c302d531:[()=>n.e(9366).then(n.bind(n,437)),"@site/docs/solide-dapp/translate-your-site.md",437],cae0def9:[()=>n.e(6474).then(n.t.bind(n,9200,19)),"~blog/default/doc-blog-tags-open-source-f4a-list.json",9200],ccc49370:[()=>Promise.all([n.e(1869),n.e(2125),n.e(8747),n.e(3249)]).then(n.bind(n,4029)),"@theme/BlogPostPage",4029],d6f91429:[()=>n.e(3498).then(n.t.bind(n,4061,19)),"C:\\Users\\Peter\\Documents\\app\\solide\\docs\\.docusaurus\\docusaurus-plugin-content-pages\\default\\plugin-route-context-module-100.json",4061],e3cc388d:[()=>n.e(7592).then(n.t.bind(n,2945,19)),"C:\\Users\\Peter\\Documents\\app\\solide\\docs\\.docusaurus\\docusaurus-plugin-content-blog\\default\\plugin-route-context-module-100.json",2945],e417d728:[()=>n.e(2361).then(n.t.bind(n,2958,19)),"~blog/default/doc-blog-archive-b2d.json",2958],e42daf43:[()=>n.e(7184).then(n.t.bind(n,5326,19)),"~blog/default/doc-blog-tags-open-source-f4a.json",5326],eb12263a:[()=>n.e(9959).then(n.t.bind(n,1547,19)),"~blog/default/doc-blog-tags-entry-point-f13.json",1547],ebaab4be:[()=>n.e(9349).then(n.t.bind(n,2425,19)),"~blog/default/doc-blog-tags-smart-contract-817-list.json",2425],f10b1742:[()=>n.e(2012).then(n.t.bind(n,1436,19)),"~blog/default/doc-blog-tags-development-tool-4eb-list.json",1436],f70f6443:[()=>n.e(7553).then(n.t.bind(n,5676,19)),"~blog/default/doc-blog-cc9.json",5676]};var l=n(4848);function s(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,l.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,l.jsx)("p",{children:String(t)}),(0,l.jsx)("div",{children:(0,l.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,l.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,l.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,l.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,l.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var c=n(6921),u=n(3102);function d(e,t){if("*"===e)return o()({loading:s,loader:()=>n.e(2237).then(n.bind(n,2237)),modules:["@theme/NotFound"],webpack:()=>[2237],render(e,t){const n=e.default;return(0,l.jsx)(u.W,{value:{plugin:{name:"native",id:"default"}},children:(0,l.jsx)(n,{...t})})}});const r=a[`${e}-${t}`],d={},f=[],p=[],g=(0,c.A)(r);return Object.entries(g).forEach((e=>{let[t,n]=e;const r=i[n];r&&(d[t]=r[0],f.push(r[1]),p.push(r[2]))})),o().Map({loading:s,loader:d,modules:f,webpack:()=>p,render(t,n){const o=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let i=o;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=a}));const a=o.__comp;delete o.__comp;const i=o.__context;return delete o.__context,(0,l.jsx)(u.W,{value:i,children:(0,l.jsx)(a,{...o,...n})})}})}const f=[{path:"/doc/blog",component:d("/doc/blog","2d7"),exact:!0},{path:"/doc/blog/archive",component:d("/doc/blog/archive","7b5"),exact:!0},{path:"/doc/blog/ethereum/erc4337/entrypoint",component:d("/doc/blog/ethereum/erc4337/entrypoint","328"),exact:!0},{path:"/doc/blog/ethereum/erc4337/paymaster",component:d("/doc/blog/ethereum/erc4337/paymaster","9eb"),exact:!0},{path:"/doc/blog/tags",component:d("/doc/blog/tags","095"),exact:!0},{path:"/doc/blog/tags/account-abstraction",component:d("/doc/blog/tags/account-abstraction","fa0"),exact:!0},{path:"/doc/blog/tags/development-tool",component:d("/doc/blog/tags/development-tool","45f"),exact:!0},{path:"/doc/blog/tags/entry-point",component:d("/doc/blog/tags/entry-point","baf"),exact:!0},{path:"/doc/blog/tags/erc-4337",component:d("/doc/blog/tags/erc-4337","abd"),exact:!0},{path:"/doc/blog/tags/ethereum",component:d("/doc/blog/tags/ethereum","462"),exact:!0},{path:"/doc/blog/tags/open-source",component:d("/doc/blog/tags/open-source","c43"),exact:!0},{path:"/doc/blog/tags/smart-contract",component:d("/doc/blog/tags/smart-contract","5de"),exact:!0},{path:"/doc/blog/welcome",component:d("/doc/blog/welcome","caf"),exact:!0},{path:"/doc/markdown-page",component:d("/doc/markdown-page","c78"),exact:!0},{path:"/doc/docs",component:d("/doc/docs","641"),routes:[{path:"/doc/docs",component:d("/doc/docs","3f5"),routes:[{path:"/doc/docs",component:d("/doc/docs","95d"),routes:[{path:"/doc/docs/intro",component:d("/doc/docs/intro","464"),exact:!0,sidebar:"tutorialSidebar"},{path:"/doc/docs/solide-dapp/manage-docs-versions",component:d("/doc/docs/solide-dapp/manage-docs-versions","5d3"),exact:!0},{path:"/doc/docs/solide-dapp/translate-your-site",component:d("/doc/docs/solide-dapp/translate-your-site","80f"),exact:!0},{path:"/doc/docs/solide-ide/aspect-ide",component:d("/doc/docs/solide-ide/aspect-ide","a8b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/doc/docs/solide-ide/load-contract-source",component:d("/doc/docs/solide-ide/load-contract-source","13a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/doc/docs/solide-ide/load-github-source",component:d("/doc/docs/solide-ide/load-github-source","288"),exact:!0,sidebar:"tutorialSidebar"},{path:"/doc/docs/supported-chains",component:d("/doc/docs/supported-chains","3a0"),exact:!0,sidebar:"tutorialSidebar"}]}]}]},{path:"/doc/",component:d("/doc/","92b"),exact:!0},{path:"*",component:d("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>a,x:()=>i});var r=n(6540),o=n(4848);const a=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),(0,o.jsx)(a.Provider,{value:n,children:t})}},8536:(e,t,n)=>{"use strict";var r=n(6540),o=n(5338),a=n(4625),i=n(545),l=n(8193);const s=[n(119),n(6134),n(6294),n(1043)];var c=n(8328),u=n(6347),d=n(2831),f=n(4848);function p(e){let{children:t}=e;return(0,f.jsx)(f.Fragment,{children:t})}var g=n(5260),h=n(4586),m=n(6025),y=n(6342),b=n(1003),v=n(2131),w=n(4090),k=n(2967),x=n(440),S=n(1463);function E(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,h.A)(),r=(0,v.o)(),o=n[e].htmlLang,a=e=>e.replace("-","_");return(0,f.jsxs)(g.A,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,f.jsx)("meta",{property:"og:locale",content:a(o)}),Object.values(n).filter((e=>o!==e.htmlLang)).map((e=>(0,f.jsx)("meta",{property:"og:locale:alternate",content:a(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,h.A)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,h.A)(),{pathname:r}=(0,u.zy)();return e+(0,x.applyTrailingSlash)((0,m.A)(r),{trailingSlash:n,baseUrl:t})}(),o=t?`${n}${t}`:r;return(0,f.jsxs)(g.A,{children:[(0,f.jsx)("meta",{property:"og:url",content:o}),(0,f.jsx)("link",{rel:"canonical",href:o})]})}function C(){const{i18n:{currentLocale:e}}=(0,h.A)(),{metadata:t,image:n}=(0,y.p)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(g.A,{children:[(0,f.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,f.jsx)("body",{className:w.w})]}),n&&(0,f.jsx)(b.be,{image:n}),(0,f.jsx)(_,{}),(0,f.jsx)(E,{}),(0,f.jsx)(S.A,{tag:k.Cy,locale:e}),(0,f.jsx)(g.A,{children:t.map(((e,t)=>(0,f.jsx)("meta",{...e},t)))})]})}const A=new Map;function T(e){if(A.has(e.pathname))return{...e,pathname:A.get(e.pathname)};if((0,d.u)(c.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return A.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return A.set(e.pathname,t),{...e,pathname:t}}var j=n(6125),N=n(6988),L=n(205);function O(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>o.forEach((e=>e?.()))}const P=function(e){let{children:t,location:n,previousLocation:r}=e;return(0,L.A)((()=>{r!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,o=t.hash===n.hash,a=t.search===n.search;if(r&&o&&!a)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:r}),O("onRouteDidUpdate",{previousLocation:r,location:n}))}),[r,n]),t};function R(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.u)(c.A,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class I extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.A.canUseDOM?O("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=O("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),R(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return(0,f.jsx)(P,{previousLocation:this.previousLocation,location:t,children:(0,f.jsx)(u.qh,{location:t,render:()=>e})})}}const F=I,M="__docusaurus-base-url-issue-banner-container",D="__docusaurus-base-url-issue-banner",z="__docusaurus-base-url-issue-banner-suggestion-container";function B(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '${M}';\n var bannerHtml = ${JSON.stringify(function(e){return`\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const o=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;o?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var K=n(6921);const Z=new Set,X=new Set,J=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,ee={prefetch(e){if(!(e=>!J()&&!X.has(e)&&!Z.has(e))(e))return!1;Z.add(e);const t=(0,d.u)(c.A,e).flatMap((e=>{return t=e.route.path,Object.entries(Y).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,K.A)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Q(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!J()&&!X.has(e))(e)&&(X.add(e),R(e))},te=Object.freeze(ee),ne=Boolean(!0);if(l.A.canUseDOM){window.docusaurus=te;const e=document.getElementById("__docusaurus"),t=(0,f.jsx)(i.vd,{children:(0,f.jsx)(a.Kd,{children:(0,f.jsx)(G,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},l=()=>{if(ne)r.startTransition((()=>{o.hydrateRoot(e,t,{onRecoverableError:n})}));else{const a=o.createRoot(e,{onRecoverableError:n});r.startTransition((()=>{a.render(t)}))}};R(window.location.pathname).then(l)}},6988:(e,t,n)=>{"use strict";n.d(t,{o:()=>d,l:()=>f});var r=n(6540),o=n(4784);const a=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/doc/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/doc/docs","mainDocId":"intro","docs":[{"id":"intro","path":"/doc/docs/intro","sidebar":"tutorialSidebar"},{"id":"solide-dapp/manage-docs-versions","path":"/doc/docs/solide-dapp/manage-docs-versions"},{"id":"solide-dapp/translate-your-site","path":"/doc/docs/solide-dapp/translate-your-site"},{"id":"solide-ide/aspect-ide","path":"/doc/docs/solide-ide/aspect-ide","sidebar":"tutorialSidebar"},{"id":"solide-ide/load-contract-source","path":"/doc/docs/solide-ide/load-contract-source","sidebar":"tutorialSidebar"},{"id":"solide-ide/load-github-source","path":"/doc/docs/solide-ide/load-github-source","sidebar":"tutorialSidebar"},{"id":"supported-chains","path":"/doc/docs/supported-chains","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/doc/docs/intro","label":"intro"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(2654);const s=JSON.parse('{"docusaurusVersion":"3.1.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"3.1.1"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"3.1.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.1.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.1.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.1.1"},"docusaurus-tailwindcss":{"type":"local"}}}');var c=n(4848);const u={siteConfig:o.default,siteMetadata:s,globalData:a,i18n:i,codeTranslations:l},d=r.createContext(u);function f(e){let{children:t}=e;return(0,c.jsx)(d.Provider,{value:u,children:t})}},7489:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});var r=n(6540),o=n(8193),a=n(5260),i=n(440),l=n(2637),s=n(4848);function c(e){let{error:t,tryAgain:n}=e;return(0,s.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,s.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,s.jsx)("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,s.jsx)(u,{error:t})]})}function u(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,s.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:n})}function d(e){let{error:t,tryAgain:n}=e;return(0,s.jsxs)(p,{fallback:()=>(0,s.jsx)(c,{error:t,tryAgain:n}),children:[(0,s.jsx)(a.A,{children:(0,s.jsx)("title",{children:"Page Error"})}),(0,s.jsx)(l.A,{children:(0,s.jsx)(c,{error:t,tryAgain:n})})]})}const f=e=>(0,s.jsx)(d,{...e});class p extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){o.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??f)(e)}return e??null}}},8193:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,o={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5260:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(6540);var r=n(545),o=n(4848);function a(e){return(0,o.jsx)(r.mg,{...e})}},8774:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});var r=n(6540),o=n(4625),a=n(440),i=n(4586),l=n(6654),s=n(8193),c=n(3427),u=n(6025),d=n(4848);function f(e,t){let{isNavLink:n,to:f,href:p,activeClassName:g,isActive:h,"data-noBrokenLinkCheck":m,autoAddBaseUrl:y=!0,...b}=e;const{siteConfig:{trailingSlash:v,baseUrl:w}}=(0,i.A)(),{withBaseUrl:k}=(0,u.h)(),x=(0,c.A)(),S=(0,r.useRef)(null);(0,r.useImperativeHandle)(t,(()=>S.current));const E=f||p;const _=(0,l.A)(E),C=E?.replace("pathname://","");let A=void 0!==C?(T=C,y&&(e=>e.startsWith("/"))(T)?k(T):T):void 0;var T;A&&_&&(A=(0,a.applyTrailingSlash)(A,{trailingSlash:v,baseUrl:w}));const j=(0,r.useRef)(!1),N=n?o.k2:o.N_,L=s.A.canUseIntersectionObserver,O=(0,r.useRef)(),P=()=>{j.current||null==A||(window.docusaurus.preload(A),j.current=!0)};(0,r.useEffect)((()=>(!L&&_&&null!=A&&window.docusaurus.prefetch(A),()=>{L&&O.current&&O.current.disconnect()})),[O,A,L,_]);const R=A?.startsWith("#")??!1,I=!b.target||"_self"===b.target,F=!A||!_||!I||R;return m||!R&&F||x.collectLink(A),b.id&&x.collectAnchor(b.id),F?(0,d.jsx)("a",{ref:S,href:A,...E&&!_&&{target:"_blank",rel:"noopener noreferrer"},...b}):(0,d.jsx)(N,{...b,onMouseEnter:P,onTouchStart:P,innerRef:e=>{S.current=e,L&&e&&_&&(O.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(O.current.unobserve(e),O.current.disconnect(),null!=A&&window.docusaurus.prefetch(A))}))})),O.current.observe(e))},to:A,...n&&{isActive:h,activeClassName:g}})}const p=r.forwardRef(f)},418:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const r=()=>null},1312:(e,t,n)=>{"use strict";n.d(t,{A:()=>c,T:()=>s});var r=n(6540),o=n(4848);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(2654);function l(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function s(e,t){let{message:n,id:r}=e;return a(l({message:n,id:r}),t)}function c(e){let{children:t,id:n,values:r}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const i=l({message:t,id:n});return(0,o.jsx)(o.Fragment,{children:a(i,r)})}},7065:(e,t,n)=>{"use strict";n.d(t,{W:()=>r});const r="default"},6654:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function o(e){return void 0!==e&&!r(e)}n.d(t,{A:()=>o,z:()=>r})},6025:(e,t,n)=>{"use strict";n.d(t,{A:()=>l,h:()=>i});var r=n(6540),o=n(4586),a=n(6654);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,o.A)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:o=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,a.z)(n))return n;if(o)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},3427:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540);n(4848);const o=r.createContext({collectAnchor:()=>{},collectLink:()=>{}}),a=()=>(0,r.useContext)(o);function i(){return a()}},4586:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(6540),o=n(6988);function a(){return(0,r.useContext)(o.o)}},2303:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(6540),o=n(6125);function a(){return(0,r.useContext)(o.o)}},205:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=n(6540);const o=n(8193).A.canUseDOM?r.useLayoutEffect:r.useEffect},6921:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function o(e){const t={};return function e(n,o){Object.entries(n).forEach((n=>{let[a,i]=n;const l=o?`${o}.${a}`:a;r(i)?e(i,l):t[l]=i}))}(e),t}},3102:(e,t,n)=>{"use strict";n.d(t,{W:()=>i,o:()=>a});var r=n(6540),o=n(4848);const a=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(a),l=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return(0,o.jsx)(a.Provider,{value:l,children:t})}},4070:(e,t,n)=>{"use strict";n.d(t,{zK:()=>h,vT:()=>f,Gy:()=>u,HW:()=>m,ht:()=>d,r7:()=>g,jh:()=>p});var r=n(6347),o=n(4586),a=n(7065);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,o.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=function(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.B6)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),o=n?.docs.find((e=>!!(0,r.B6)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:o,alternateDocVersions:o?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(o.id):{}}}const c={},u=()=>i("docusaurus-plugin-content-docs")??c,d=e=>function(e,t,n){void 0===t&&(t=a.W),void 0===n&&(n={});const r=i(e),o=r?.[t];if(!o&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return o}("docusaurus-plugin-content-docs",e,{failfast:!0});function f(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.zy)();return function(e,t,n){void 0===n&&(n={});const o=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.B6)(t,{path:n.path,exact:!1,strict:!1})})),a=o?{pluginId:o[0],pluginData:o[1]}:void 0;if(!a&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return a}(t,n,e)}function p(e){return d(e).versions}function g(e){const t=d(e);return l(t)}function h(e){const t=d(e),{pathname:n}=(0,r.zy)();return s(t,n)}function m(e){const t=d(e),{pathname:n}=(0,r.zy)();return function(e,t){const n=l(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},6294:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>a});var r=n(5947),o=n.n(r);o().configure({showSpinner:!1});const a={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{o().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){o().done()}}},6134:(e,t,n)=>{"use strict";n.r(t);var r=n(1765),o=n(4784);!function(e){const{themeConfig:{prism:t}}=o.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{"php"===e&&n(9700),n(3845)(`./prism-${e}`)})),delete globalThis.Prism}(r.My)},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});n(6540);var r=n(4164),o=n(1312),a=n(6342),i=n(8774),l=n(3427);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var c=n(4848);function u(e){let{as:t,id:n,...u}=e;const d=(0,l.A)(),{navbar:{hideOnScroll:f}}=(0,a.p)();if("h1"===t||!n)return(0,c.jsx)(t,{...u,id:void 0});d.collectAnchor(n);const p=(0,o.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof u.children?u.children:n});return(0,c.jsxs)(t,{...u,className:(0,r.A)("anchor",f?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,u.className),id:n,children:[u.children,(0,c.jsx)(i.A,{className:"hash-link",to:`#${n}`,"aria-label":p,title:p,children:"\u200b"})]})}},3186:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(6540);const r={iconExternalLink:"iconExternalLink_nPIU"};var o=n(4848);function a(e){let{width:t=13.5,height:n=13.5}=e;return(0,o.jsx)("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:r.iconExternalLink,children:(0,o.jsx)("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"})})}},2637:(e,t,n)=>{"use strict";n.d(t,{A:()=>Je});var r=n(6540),o=n(4164),a=n(7489),i=n(1003),l=n(6347),s=n(1312),c=n(5062),u=n(4848);const d="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,l.W6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)}),[]);return(0,c.$)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const g=(0,s.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??g,{containerRef:n,onClick:r}=p();return(0,u.jsx)("div",{ref:n,role:"region","aria-label":g,children:(0,u.jsx)("a",{...e,href:`#${d}`,onClick:r,children:t})})}var m=n(7559),y=n(4090);const b={skipToContent:"skipToContent_fXgn"};function v(){return(0,u.jsx)(h,{className:b.skipToContent})}var w=n(6342),k=n(5041);function x(e){let{width:t=21,height:n=21,color:r="currentColor",strokeWidth:o=1.2,className:a,...i}=e;return(0,u.jsx)("svg",{viewBox:"0 0 15 15",width:t,height:n,...i,children:(0,u.jsx)("g",{stroke:r,strokeWidth:o,children:(0,u.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const S={closeButton:"closeButton_CVFx"};function E(e){return(0,u.jsx)("button",{type:"button","aria-label":(0,s.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,o.A)("clean-btn close",S.closeButton,e.className),children:(0,u.jsx)(x,{width:14,height:14,strokeWidth:3.1})})}const _={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,w.p)(),{content:n}=t;return(0,u.jsx)("div",{...e,className:(0,o.A)(_.content,e.className),dangerouslySetInnerHTML:{__html:n}})}const A={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function T(){const{announcementBar:e}=(0,w.p)(),{isActive:t,close:n}=(0,k.Mj)();if(!t)return null;const{backgroundColor:r,textColor:o,isCloseable:a}=e;return(0,u.jsxs)("div",{className:A.announcementBar,style:{backgroundColor:r,color:o},role:"banner",children:[a&&(0,u.jsx)("div",{className:A.announcementBarPlaceholder}),(0,u.jsx)(C,{className:A.announcementBarContent}),a&&(0,u.jsx)(E,{onClick:n,className:A.announcementBarClose})]})}var j=n(9876),N=n(3104);var L=n(9532),O=n(5600);const P=r.createContext(null);function R(e){let{children:t}=e;const n=function(){const e=(0,j.M)(),t=(0,O.YL)(),[n,o]=(0,r.useState)(!1),a=null!==t.component,i=(0,L.ZC)(a);return(0,r.useEffect)((()=>{a&&!i&&o(!0)}),[a,i]),(0,r.useEffect)((()=>{a?e.shown||o(!0):o(!1)}),[e.shown,a]),(0,r.useMemo)((()=>[n,o]),[n])}();return(0,u.jsx)(P.Provider,{value:n,children:t})}function I(e){if(e.component){const t=e.component;return(0,u.jsx)(t,{...e.props})}}function F(){const e=(0,r.useContext)(P);if(!e)throw new L.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,o=(0,r.useCallback)((()=>n(!1)),[n]),a=(0,O.YL)();return(0,r.useMemo)((()=>({shown:t,hide:o,content:I(a)})),[o,a,t])}function M(e){let{header:t,primaryMenu:n,secondaryMenu:r}=e;const{shown:a}=F();return(0,u.jsxs)("div",{className:"navbar-sidebar",children:[t,(0,u.jsxs)("div",{className:(0,o.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":a}),children:[(0,u.jsx)("div",{className:"navbar-sidebar__item menu",children:n}),(0,u.jsx)("div",{className:"navbar-sidebar__item menu",children:r})]})]})}var D=n(5293),z=n(2303);function B(e){return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,u.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function $(e){return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,u.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}const U={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function H(e){let{className:t,buttonClassName:n,value:r,onChange:a}=e;const i=(0,z.A)(),l=(0,s.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===r?(0,s.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,s.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return(0,u.jsx)("div",{className:(0,o.A)(U.toggle,t),children:(0,u.jsxs)("button",{className:(0,o.A)("clean-btn",U.toggleButton,!i&&U.toggleButtonDisabled,n),type:"button",onClick:()=>a("dark"===r?"light":"dark"),disabled:!i,title:l,"aria-label":l,"aria-live":"polite",children:[(0,u.jsx)(B,{className:(0,o.A)(U.toggleIcon,U.lightToggleIcon)}),(0,u.jsx)($,{className:(0,o.A)(U.toggleIcon,U.darkToggleIcon)})]})})}const V=r.memo(H),W={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function q(e){let{className:t}=e;const n=(0,w.p)().navbar.style,r=(0,w.p)().colorMode.disableSwitch,{colorMode:o,setColorMode:a}=(0,D.G)();return r?null:(0,u.jsx)(V,{className:t,buttonClassName:"dark"===n?W.darkNavbarColorModeToggle:void 0,value:o,onChange:a})}var G=n(9529);function Y(){return(0,u.jsx)(G.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function Q(){const e=(0,j.M)();return(0,u.jsx)("button",{type:"button","aria-label":(0,s.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,u.jsx)(x,{color:"var(--ifm-color-emphasis-600)"})})}function K(){return(0,u.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,u.jsx)(Y,{}),(0,u.jsx)(q,{className:"margin-right--md"}),(0,u.jsx)(Q,{})]})}var Z=n(8774),X=n(6025),J=n(6654);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(3186);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:r,href:o,label:a,html:i,isDropdownLink:l,prependBaseUrlToHref:s,...c}=e;const d=(0,X.A)(r),f=(0,X.A)(t),p=(0,X.A)(o,{forcePrependBaseUrl:!0}),g=a&&o&&!(0,J.A)(o),h=i?{dangerouslySetInnerHTML:{__html:i}}:{children:(0,u.jsxs)(u.Fragment,{children:[a,g&&(0,u.jsx)(te.A,{...l&&{width:12,height:12}})]})};return o?(0,u.jsx)(Z.A,{href:s?p:o,...c,...h}):(0,u.jsx)(Z.A,{to:d,isNavLink:!0,...(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(f)},...c,...h})}function re(e){let{className:t,isDropdownItem:n=!1,...r}=e;const a=(0,u.jsx)(ne,{className:(0,o.A)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n,...r});return n?(0,u.jsx)("li",{children:a}):a}function oe(e){let{className:t,isDropdownItem:n,...r}=e;return(0,u.jsx)("li",{className:"menu__list-item",children:(0,u.jsx)(ne,{className:(0,o.A)("menu__link",t),...r})})}function ae(e){let{mobile:t=!1,position:n,...r}=e;const o=t?oe:re;return(0,u.jsx)(o,{...r,activeClassName:r.activeClassName??(t?"menu__link--active":"navbar__link--active")})}var ie=n(1422),le=n(9169),se=n(4586);const ce={dropdownNavbarItemMobile:"dropdownNavbarItemMobile_S0Fm"};function ue(e,t){return e.some((e=>function(e,t){return!!(0,le.ys)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function de(e){let{items:t,position:n,className:a,onClick:i,...l}=e;const s=(0,r.useRef)(null),[c,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{s.current&&!s.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[s]),(0,u.jsxs)("div",{ref:s,className:(0,o.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":c}),children:[(0,u.jsx)(ne,{"aria-haspopup":"true","aria-expanded":c,role:"button",href:l.to?void 0:"#",className:(0,o.A)("navbar__link",a),...l,onClick:l.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!c))},children:l.children??l.label}),(0,u.jsx)("ul",{className:"dropdown__menu",children:t.map(((e,t)=>(0,r.createElement)(_e,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t})))})]})}function fe(e){let{items:t,className:n,position:a,onClick:i,...s}=e;const c=function(){const{siteConfig:{baseUrl:e}}=(0,se.A)(),{pathname:t}=(0,l.zy)();return t.replace(e,"/")}(),d=ue(t,c),{collapsed:f,toggleCollapsed:p,setCollapsed:g}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&g(!d)}),[c,d,g]),(0,u.jsxs)("li",{className:(0,o.A)("menu__list-item",{"menu__list-item--collapsed":f}),children:[(0,u.jsx)(ne,{role:"button",className:(0,o.A)(ce.dropdownNavbarItemMobile,"menu__link menu__link--sublist menu__link--sublist-caret",n),...s,onClick:e=>{e.preventDefault(),p()},children:s.children??s.label}),(0,u.jsx)(ie.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:f,children:t.map(((e,t)=>(0,r.createElement)(_e,{mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active",...e,key:t})))})]})}function pe(e){let{mobile:t=!1,...n}=e;const r=t?fe:de;return(0,u.jsx)(r,{...n})}var ge=n(2131);function he(e){let{width:t=20,height:n=20,...r}=e;return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0,...r,children:(0,u.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const me="iconLanguage_nlXk";var ye=n(418);const be={navbarSearchContainer:"navbarSearchContainer_Bca1"};function ve(e){let{children:t,className:n}=e;return(0,u.jsx)("div",{className:(0,o.A)(n,be.navbarSearchContainer),children:t})}var we=n(4070),ke=n(1754);var xe=n(5597);const Se=e=>e.docs.find((t=>t.id===e.mainDocId));const Ee={default:ae,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:r,queryString:o="",...a}=e;const{i18n:{currentLocale:i,locales:c,localeConfigs:d}}=(0,se.A)(),f=(0,ge.o)(),{search:p,hash:g}=(0,l.zy)(),h=[...n,...c.map((e=>{const n=`${`pathname://${f.createUrl({locale:e,fullyQualified:!1})}`}${p}${g}${o}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...r],m=t?(0,s.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return(0,u.jsx)(pe,{...a,mobile:t,label:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(he,{className:me}),m]}),items:h})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,u.jsx)(ve,{className:n,children:(0,u.jsx)(ye.A,{})})},dropdown:pe,html:function(e){let{value:t,className:n,mobile:r=!1,isDropdownItem:a=!1}=e;const i=a?"li":"div";return(0,u.jsx)(i,{className:(0,o.A)({navbar__item:!r&&!a,"menu__list-item":r},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:r,...o}=e;const{activeDoc:a}=(0,we.zK)(r),i=(0,ke.QB)(t,r),l=a?.path===i?.path;return null===i||i.unlisted&&!l?null:(0,u.jsx)(ae,{exact:!0,...o,isActive:()=>l||!!a?.sidebar&&a.sidebar===i.sidebar,label:n??i.id,to:i.path})},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:r,...o}=e;const{activeDoc:a}=(0,we.zK)(r),i=(0,ke.fW)(t,r).link;if(!i)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return(0,u.jsx)(ae,{exact:!0,...o,isActive:()=>a?.sidebar===t,label:n??i.label,to:i.path})},docsVersion:function(e){let{label:t,to:n,docsPluginId:r,...o}=e;const a=(0,ke.Vd)(r)[0],i=t??a.label,l=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(a).path;return(0,u.jsx)(ae,{...o,label:i,to:l})},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:r,dropdownItemsBefore:o,dropdownItemsAfter:a,...i}=e;const{search:c,hash:d}=(0,l.zy)(),f=(0,we.zK)(n),p=(0,we.jh)(n),{savePreferredVersionName:g}=(0,xe.g1)(n),h=[...o,...p.map((e=>{const t=f.alternateDocVersions[e.name]??Se(e);return{label:e.label,to:`${t.path}${c}${d}`,isActive:()=>e===f.activeVersion,onClick:()=>g(e.name)}})),...a],m=(0,ke.Vd)(n)[0],y=t&&h.length>1?(0,s.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):m.label,b=t&&h.length>1?void 0:Se(m).path;return h.length<=1?(0,u.jsx)(ae,{...i,mobile:t,label:y,to:b,isActive:r?()=>!1:void 0}):(0,u.jsx)(pe,{...i,mobile:t,label:y,to:b,items:h,isActive:r?()=>!1:void 0})}};function _e(e){let{type:t,...n}=e;const r=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=Ee[r];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return(0,u.jsx)(o,{...n})}function Ce(){const e=(0,j.M)(),t=(0,w.p)().navbar.items;return(0,u.jsx)("ul",{className:"menu__list",children:t.map(((t,n)=>(0,r.createElement)(_e,{mobile:!0,...t,onClick:()=>e.toggle(),key:n})))})}function Ae(e){return(0,u.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,u.jsx)(s.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function Te(){const e=0===(0,w.p)().navbar.items.length,t=F();return(0,u.jsxs)(u.Fragment,{children:[!e&&(0,u.jsx)(Ae,{onClick:()=>t.hide()}),t.content]})}function je(){const e=(0,j.M)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?(0,u.jsx)(M,{header:(0,u.jsx)(K,{}),primaryMenu:(0,u.jsx)(Ce,{}),secondaryMenu:(0,u.jsx)(Te,{})}):null}const Ne={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Le(e){return(0,u.jsx)("div",{role:"presentation",...e,className:(0,o.A)("navbar-sidebar__backdrop",e.className)})}function Oe(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:a}}=(0,w.p)(),i=(0,j.M)(),{navbarRef:l,isNavbarVisible:d}=function(e){const[t,n]=(0,r.useState)(e),o=(0,r.useRef)(!1),a=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(a.current=e.getBoundingClientRect().height)}),[]);return(0,N.Mq)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+c{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return o.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return(0,u.jsxs)("nav",{ref:l,"aria-label":(0,s.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,o.A)("navbar","navbar--fixed-top",n&&[Ne.navbarHideable,!d&&Ne.navbarHidden],{"navbar--dark":"dark"===a,"navbar--primary":"primary"===a,"navbar-sidebar--show":i.shown}),children:[t,(0,u.jsx)(Le,{onClick:i.toggle}),(0,u.jsx)(je,{})]})}var Pe=n(440);const Re={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function Ie(e){return(0,u.jsx)("button",{type:"button",...e,children:(0,u.jsx)(s.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function Fe(e){let{error:t}=e;const n=(0,Pe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,u.jsx)("p",{className:Re.errorBoundaryError,children:n})}class Me extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const De="right";function ze(e){let{width:t=30,height:n=30,className:r,...o}=e;return(0,u.jsx)("svg",{className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...o,children:(0,u.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function Be(){const{toggle:e,shown:t}=(0,j.M)();return(0,u.jsx)("button",{onClick:e,"aria-label":(0,s.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,u.jsx)(ze,{})})}const $e={colorModeToggle:"colorModeToggle_DEke"};function Ue(e){let{items:t}=e;return(0,u.jsx)(u.Fragment,{children:t.map(((e,t)=>(0,u.jsx)(Me,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,u.jsx)(_e,{...e})},t)))})}function He(e){let{left:t,right:n}=e;return(0,u.jsxs)("div",{className:"navbar__inner",children:[(0,u.jsx)("div",{className:"navbar__items",children:t}),(0,u.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function Ve(){const e=(0,j.M)(),t=(0,w.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??De)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return(0,u.jsx)(He,{left:(0,u.jsxs)(u.Fragment,{children:[!e.disabled&&(0,u.jsx)(Be,{}),(0,u.jsx)(Y,{}),(0,u.jsx)(Ue,{items:n})]}),right:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(Ue,{items:r}),(0,u.jsx)(q,{className:$e.colorModeToggle}),!o&&(0,u.jsx)(ve,{children:(0,u.jsx)(ye.A,{})})]})})}function We(){return(0,u.jsx)(Oe,{children:(0,u.jsx)(Ve,{})})}var qe=n(5066);function Ge(e){const{siteConfig:t}=(0,se.A)(),{isDarkTheme:n}=(0,D.G)(),r=e=>{switch(e){case"Github":return"mingcute:github-line";case"X":return"akar-icons:twitter-fill";case"App":return"akar-icons:facebook-fill"}};return(0,u.jsxs)("div",{className:"grid grid-cols-12 py-8 gap-4 border-t",children:[(0,u.jsxs)("div",{className:"col-span-12 lg:col-span-4 flex items-center justify-center",children:[(0,u.jsx)(qe.In,{className:"text-primary",icon:"lucide:droplet",width:"32",height:"32"}),(0,u.jsx)("span",{className:"text-2xl font-semibold tracking-tight",children:"Solide"})]}),(0,u.jsx)("div",{className:"col-span-12 lg:col-span-4 flex items-center justify-center",children:(0,u.jsx)("span",{className:"",children:"Made with \u2764\ufe0f by Solide Project"})}),(0,u.jsx)("div",{className:"col-span-12 lg:col-span-4 flex items-center justify-center",children:(0,u.jsx)("div",{className:"flex gap-2",children:t.themeConfig.footer.links.map((e=>(0,u.jsx)(Z.A,{to:e.to,children:(0,u.jsx)(qe.In,{icon:r(e.label),fontSize:24,color:n?"white":"black",size:16})},e.label)))})})]})}const Ye=(0,L.fM)([D.a,k.oq,N.Tv,xe.VQ,i.Jx,function(e){let{children:t}=e;return(0,u.jsx)(O.y_,{children:(0,u.jsx)(j.e,{children:(0,u.jsx)(R,{children:t})})})}]);function Qe(e){let{children:t}=e;return(0,u.jsx)(Ye,{children:t})}var Ke=n(1107);function Ze(e){let{error:t,tryAgain:n}=e;return(0,u.jsx)("main",{className:"container margin-vert--xl",children:(0,u.jsx)("div",{className:"row",children:(0,u.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,u.jsx)(Ke.A,{as:"h1",className:"hero__title",children:(0,u.jsx)(s.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,u.jsx)("div",{className:"margin-vert--lg",children:(0,u.jsx)(Ie,{onClick:n,className:"button button--primary shadow--lw"})}),(0,u.jsx)("hr",{}),(0,u.jsx)("div",{className:"margin-vert--md",children:(0,u.jsx)(Fe,{error:t})})]})})})}const Xe={mainWrapper:"mainWrapper_z2l0"};function Je(e){const{children:t,noFooter:n,wrapperClassName:r,title:l,description:s}=e;return(0,y.J)(),(0,u.jsxs)(Qe,{children:[(0,u.jsx)(i.be,{title:l,description:s}),(0,u.jsx)(v,{}),(0,u.jsx)(T,{}),(0,u.jsx)(We,{}),(0,u.jsx)("div",{id:d,className:(0,o.A)(m.G.wrapper.main,Xe.mainWrapper,r),children:(0,u.jsx)(a.A,{fallback:e=>(0,u.jsx)(Ze,{...e}),children:t})}),!n&&(0,u.jsx)(Ge,{})]})}},9529:(e,t,n)=>{"use strict";n.d(t,{A:()=>m});var r=n(6540),o=n(8774),a=n(6025),i=n(4586),l=n(6342),s=n(4164),c=n(2303),u=n(5293);const d={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var f=n(4848);function p(e){let{className:t,children:n}=e;const o=(0,c.A)(),{colorMode:a}=(0,u.G)();return(0,f.jsx)(f.Fragment,{children:(o?"dark"===a?["dark"]:["light"]:["light","dark"]).map((e=>{const o=n({theme:e,className:(0,s.A)(t,d.themedComponent,d[`themedComponent--${e}`])});return(0,f.jsx)(r.Fragment,{children:o},e)}))})}function g(e){const{sources:t,className:n,alt:r,...o}=e;return(0,f.jsx)(p,{className:n,children:e=>{let{theme:n,className:a}=e;return(0,f.jsx)("img",{src:t[n],alt:r,className:a,...o})}})}function h(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,a.A)(t.src),dark:(0,a.A)(t.srcDark||t.src)},i=(0,f.jsx)(g,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?(0,f.jsx)("div",{className:r,children:i}):i}function m(e){const{siteConfig:{title:t}}=(0,i.A)(),{navbar:{title:n,logo:r}}=(0,l.p)(),{imageClassName:s,titleClassName:c,...u}=e,d=(0,a.A)(r?.href||"/"),p=n?"":t,g=r?.alt??p;return(0,f.jsxs)(o.A,{to:d,...u,...r?.target&&{target:r.target},children:[r&&(0,f.jsx)(h,{logo:r,alt:g,imageClassName:s}),null!=n&&(0,f.jsx)("b",{className:c,children:n})]})}},1463:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(6540);var r=n(5260),o=n(4848);function a(e){let{locale:t,version:n,tag:a}=e;const i=t;return(0,o.jsxs)(r.A,{children:[t&&(0,o.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,o.jsx)("meta",{name:"docusaurus_version",content:n}),a&&(0,o.jsx)("meta",{name:"docusaurus_tag",content:a}),i&&(0,o.jsx)("meta",{name:"docsearch:language",content:i}),n&&(0,o.jsx)("meta",{name:"docsearch:version",content:n}),a&&(0,o.jsx)("meta",{name:"docsearch:docusaurus_tag",content:a})]})}},1422:(e,t,n)=>{"use strict";n.d(t,{N:()=>y,u:()=>c});var r=n(6540),o=n(8193),a=n(205),i=n(3109),l=n(4848);const s="ease-in-out";function c(e){let{initialState:t}=e;const[n,o]=(0,r.useState)(t??!1),a=(0,r.useCallback)((()=>{o((e=>!e))}),[]);return{collapsed:n,setCollapsed:o,toggleCollapsed:a}}const u={display:"none",overflow:"hidden",height:"0px"},d={display:"block",overflow:"visible",height:"auto"};function f(e,t){const n=t?u:d;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p(e){let{collapsibleRef:t,collapsed:n,animation:o}=e;const a=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=e.scrollHeight,n=o?.duration??function(e){if((0,i.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${o?.easing??s}`,height:`${t}px`}}function l(){const t=r();e.style.transition=t.transition,e.style.height=t.height}if(!a.current)return f(e,n),void(a.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=u.height,e.style.overflow=u.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,o])}function g(e){if(!o.A.canUseDOM)return e?u:d}function h(e){let{as:t="div",collapsed:n,children:o,animation:a,onCollapseTransitionEnd:i,className:s,disableSSRStyle:c}=e;const u=(0,r.useRef)(null);return p({collapsibleRef:u,collapsed:n,animation:a}),(0,l.jsx)(t,{ref:u,style:c?void 0:g(n),onTransitionEnd:e=>{"height"===e.propertyName&&(f(u.current,n),i?.(n))},className:s,children:o})}function m(e){let{collapsed:t,...n}=e;const[o,i]=(0,r.useState)(!t),[s,c]=(0,r.useState)(t);return(0,a.A)((()=>{t||i(!0)}),[t]),(0,a.A)((()=>{o&&c(t)}),[o,t]),o?(0,l.jsx)(h,{...n,collapsed:s}):null}function y(e){let{lazy:t,...n}=e;const r=t?m:h;return(0,l.jsx)(r,{...n})}},5041:(e,t,n)=>{"use strict";n.d(t,{Mj:()=>h,oq:()=>g});var r=n(6540),o=n(2303),a=n(9466),i=n(9532),l=n(6342),s=n(4848);const c=(0,a.Wf)("docusaurus.announcement.dismiss"),u=(0,a.Wf)("docusaurus.announcement.id"),d=()=>"true"===c.get(),f=e=>c.set(String(e)),p=r.createContext(null);function g(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.p)(),t=(0,o.A)(),[n,a]=(0,r.useState)((()=>!!t&&d()));(0,r.useEffect)((()=>{a(d())}),[]);const i=(0,r.useCallback)((()=>{f(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&f(!1),!r&&d()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return(0,s.jsx)(p.Provider,{value:n,children:t})}function h(){const e=(0,r.useContext)(p);if(!e)throw new i.dV("AnnouncementBarProvider");return e}},5293:(e,t,n)=>{"use strict";n.d(t,{G:()=>y,a:()=>m});var r=n(6540),o=n(8193),a=n(9532),i=n(9466),l=n(6342),s=n(4848);const c=r.createContext(void 0),u="theme",d=(0,i.Wf)(u),f={light:"light",dark:"dark"},p=e=>e===f.dark?f.dark:f.light,g=e=>o.A.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),h=e=>{d.set(p(e))};function m(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.p)(),[o,a]=(0,r.useState)(g(e));(0,r.useEffect)((()=>{t&&d.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:o=!0}=r;t?(a(t),o&&h(t)):(a(n?window.matchMedia("(prefers-color-scheme: dark)").matches?f.dark:f.light:e),d.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(o))}),[o]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=d.get();null!==t&&i(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:o,setColorMode:i,get isDarkTheme(){return o===f.dark},setLightTheme(){i(f.light)},setDarkTheme(){i(f.dark)}})),[o,i])}();return(0,s.jsx)(c.Provider,{value:n,children:t})}function y(){const e=(0,r.useContext)(c);if(null==e)throw new a.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},5597:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>y,g1:()=>v});var r=n(6540),o=n(4070),a=n(7065),i=n(6342),l=n(1754),s=n(9532),c=n(9466),u=n(4848);const d=e=>`docs-preferred-version-${e}`,f={save:(e,t,n)=>{(0,c.Wf)(d(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.Wf)(d(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.Wf)(d(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const g=r.createContext(null);function h(){const e=(0,o.Gy)(),t=(0,i.p)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[a,l]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function o(e){const t=f.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(f.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,o(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[a,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){f.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function m(e){let{children:t}=e;const n=h();return(0,u.jsx)(g.Provider,{value:n,children:t})}function y(e){let{children:t}=e;return l.C5?(0,u.jsx)(m,{children:t}):(0,u.jsx)(u.Fragment,{children:t})}function b(){const e=(0,r.useContext)(g);if(!e)throw new s.dV("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=a.W);const t=(0,o.ht)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},6588:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,t:()=>c});var r=n(6540),o=n(9532),a=n(4848);const i=Symbol("EmptyContext"),l=r.createContext(i);function s(e){let{children:t,name:n,items:o}=e;const i=(0,r.useMemo)((()=>n&&o?{name:n,items:o}:null),[n,o]);return(0,a.jsx)(l.Provider,{value:i,children:t})}function c(){const e=(0,r.useContext)(l);if(e===i)throw new o.dV("DocsSidebarProvider");return e}},2252:(e,t,n)=>{"use strict";n.d(t,{n:()=>l,r:()=>s});var r=n(6540),o=n(9532),a=n(4848);const i=r.createContext(null);function l(e){let{children:t,version:n}=e;return(0,a.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(null===e)throw new o.dV("DocsVersionProvider");return e}},9876:(e,t,n)=>{"use strict";n.d(t,{e:()=>p,M:()=>g});var r=n(6540),o=n(5600),a=n(4581),i=n(6347),l=n(9532);function s(e){!function(e){const t=(0,i.W6)(),n=(0,l._q)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6342),u=n(4848);const d=r.createContext(void 0);function f(){const e=function(){const e=(0,o.YL)(),{items:t}=(0,c.p)().navbar;return 0===t.length&&!e.component}(),t=(0,a.l)(),n=!e&&"mobile"===t,[i,l]=(0,r.useState)(!1);s((()=>{if(i)return l(!1),!1}));const u=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:i})),[e,n,u,i])}function p(e){let{children:t}=e;const n=f();return(0,u.jsx)(d.Provider,{value:n,children:t})}function g(){const e=r.useContext(d);if(void 0===e)throw new l.dV("NavbarMobileSidebarProvider");return e}},5600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>c,YL:()=>s,y_:()=>l});var r=n(6540),o=n(9532),a=n(4848);const i=r.createContext(null);function l(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return(0,a.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(!e)throw new o.dV("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const a=(0,r.useContext)(i);if(!a)throw new o.dV("NavbarSecondaryMenuContentProvider");const[,l]=a,s=(0,o.Be)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},4090:(e,t,n)=>{"use strict";n.d(t,{w:()=>o,J:()=>a});var r=n(6540);const o="navigation-with-keyboard";function a(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},4581:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(6540),o=n(8193);const a={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(e){let{desktopBreakpoint:t=i}=void 0===e?{}:e;const[n,l]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function e(){l(function(e){if(!o.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>e?a.desktop:a.mobile}(t))}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[t]),n}},7559:(e,t,n)=>{"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},3109:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>r})},1754:(e,t,n)=>{"use strict";n.d(t,{Nr:()=>p,w8:()=>m,C5:()=>f,B5:()=>E,Vd:()=>k,QB:()=>S,fW:()=>x,OF:()=>w,Y:()=>b});var r=n(6540),o=n(6347),a=n(2831),i=n(4070),l=n(5597),s=n(2252),c=n(6588);function u(e){return Array.from(new Set(e))}var d=n(9169);const f=!!i.Gy;function p(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=p(t);if(e)return e}}(e):void 0:e.href}const g=(e,t)=>void 0!==e&&(0,d.ys)(e,t),h=(e,t)=>e.some((e=>m(e,t)));function m(e,t){return"link"===e.type?g(e.href,t):"category"===e.type&&(g(e.href,t)||h(e.items,t))}function y(e,t){switch(e.type){case"category":return m(e,t)||e.items.some((e=>y(e,t)));case"link":return!e.unlisted||m(e,t);default:return!0}}function b(e,t){return(0,r.useMemo)((()=>e.filter((e=>y(e,t)))),[e,t])}function v(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const o=[];return function e(t){for(const a of t)if("category"===a.type&&((0,d.ys)(a.href,n)||e(a.items))||"link"===a.type&&(0,d.ys)(a.href,n)){return r&&"category"!==a.type||o.unshift(a),!0}return!1}(t),o}function w(){const e=(0,c.t)(),{pathname:t}=(0,o.zy)(),n=(0,i.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?v({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,i.zK)(e),{preferredVersion:n}=(0,l.g1)(e),o=(0,i.r7)(e);return(0,r.useMemo)((()=>u([t,n,o].filter(Boolean))),[t,n,o])}function x(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function S(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${u(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function E(e){let{route:t}=e;const n=(0,o.zy)(),r=(0,s.r)(),i=t.routes,l=i.find((e=>(0,o.B6)(n.pathname,e)));if(!l)return null;const c=l.sidebar,u=c?r.docsSidebars[c]:void 0;return{docElement:(0,a.v)(i),sidebarName:c,sidebarItems:u}}},1003:(e,t,n)=>{"use strict";n.d(t,{e3:()=>p,be:()=>d,Jx:()=>g});var r=n(6540),o=n(4164),a=n(5260),i=n(3102);function l(){const e=r.useContext(i.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(6025),c=n(4586);var u=n(4848);function d(e){let{title:t,description:n,keywords:r,image:o,children:i}=e;const l=function(e){const{siteConfig:t}=(0,c.A)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.h)(),f=o?d(o,{absolute:!0}):void 0;return(0,u.jsxs)(a.A,{children:[t&&(0,u.jsx)("title",{children:l}),t&&(0,u.jsx)("meta",{property:"og:title",content:l}),n&&(0,u.jsx)("meta",{name:"description",content:n}),n&&(0,u.jsx)("meta",{property:"og:description",content:n}),r&&(0,u.jsx)("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),f&&(0,u.jsx)("meta",{property:"og:image",content:f}),f&&(0,u.jsx)("meta",{name:"twitter:image",content:f}),i]})}const f=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const i=r.useContext(f),l=(0,o.A)(i,t);return(0,u.jsxs)(f.Provider,{value:l,children:[(0,u.jsx)(a.A,{children:(0,u.jsx)("html",{className:l})}),n]})}function g(e){let{children:t}=e;const n=l(),r=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const a=`plugin-id-${n.plugin.id}`;return(0,u.jsx)(p,{className:(0,o.A)(r,a),children:t})}},9532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>c,ZC:()=>l,_q:()=>i,dV:()=>s,fM:()=>u});var r=n(6540),o=n(205),a=n(4848);function i(e){const t=(0,r.useRef)(e);return(0,o.A)((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function l(e){const t=(0,r.useRef)();return(0,o.A)((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function c(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function u(e){return t=>{let{children:n}=t;return(0,a.jsx)(a.Fragment,{children:e.reduceRight(((e,t)=>(0,a.jsx)(t,{children:e})),n)})}}},9169:(e,t,n)=>{"use strict";n.d(t,{Dt:()=>l,ys:()=>i});var r=n(6540),o=n(8328),a=n(4586);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,a.A)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function o(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(o).flatMap((e=>e.routes??[])))}(n)}({routes:o.A,baseUrl:e})),[e])}},3104:(e,t,n)=>{"use strict";n.d(t,{Mq:()=>f,Tv:()=>c,gk:()=>p});var r=n(6540),o=n(8193),a=n(2303),i=(n(205),n(9532)),l=n(4848);const s=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return(0,l.jsx)(s.Provider,{value:n,children:t})}function u(){const e=(0,r.useContext)(s);if(null==e)throw new i.dV("ScrollControllerProvider");return e}const d=()=>o.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function f(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=u(),o=(0,r.useRef)(d()),a=(0,i._q)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=d();a(e,o.current),o.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[a,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,a.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const o=document.documentElement.scrollTop;(n&&o>e||!n&&ot&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},2967:(e,t,n)=>{"use strict";n.d(t,{Cy:()=>r,tU:()=>o});n(4586);const r="default";function o(e,t){return`docs-${e}-${t}`}},9466:(e,t,n)=>{"use strict";n.d(t,{Wf:()=>s});n(6540);const r="localStorage";function o(e){let{key:t,oldValue:n,newValue:r,storage:o}=e;if(n===r)return;const a=document.createEvent("StorageEvent");a.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,o),window.dispatchEvent(a)}function a(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function s(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=a(t?.persistence);return null===n?l:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),o({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),o({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},2131:(e,t,n)=>{"use strict";n.d(t,{o:()=>i});var r=n(4586),o=n(6347),a=n(440);function i(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:i,currentLocale:l}}=(0,r.A)(),{pathname:s}=(0,o.zy)(),c=(0,a.applyTrailingSlash)(s,{trailingSlash:n,baseUrl:e}),u=l===i?e:e.replace(`/${l}/`,"/"),d=c.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:r}=e;return`${r?t:""}${function(e){return e===i?`${u}`:`${u}${e}/`}(n)}${d}`}}}},5062:(e,t,n)=>{"use strict";n.d(t,{$:()=>i});var r=n(6540),o=n(6347),a=n(9532);function i(e){const t=(0,o.zy)(),n=(0,a.ZC)(t),i=(0,a._q)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6342:(e,t,n)=>{"use strict";n.d(t,{p:()=>o});var r=n(4586);function o(){return(0,r.A)().siteConfig.themeConfig}},2983:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[o]=e.split(/[#?]/),a="/"===o||o===r?o:(i=o,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(o,a)}},253:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},440:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var o=n(2983);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(o).default}});var a=n(253);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return a.getErrorCausalChain}})},1513:(e,t,n)=>{"use strict";n.d(t,{zR:()=>w,TM:()=>C,yJ:()=>p,sC:()=>T,AO:()=>f});var r=n(8168);function o(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,o=e.length;r=0;f--){var p=i[f];"."===p?a(i,f):".."===p?(a(i,f),d++):d&&(a(i,f),d--)}if(!c)for(;d--;d)i.unshift("..");!c||""===i[0]||i[0]&&o(i[0])||i.unshift("");var g=i.join("/");return n&&"/"!==g.substr(-1)&&(g+="/"),g};var l=n(1561);function s(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,o=t||"/";return n&&"?"!==n&&(o+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(o+="#"===r.charAt(0)?r:"#"+r),o}function p(e,t,n,o){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",o=t.indexOf("#");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf("?");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=(0,r.A)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(a.key=n),o?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname="/"),a}function g(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,o):n.push(o),d({action:r,location:o,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",o=p(e,t,h(),w.location);u.confirmTransitionTo(o,r,n,(function(e){e&&(w.entries[w.index]=o,d({action:r,location:o}))}))},go:v,goBack:function(){v(-1)},goForward:function(){v(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(4363),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||o}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,g=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(g){var o=p(n);o&&o!==g&&e(t,o,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),h=s(n),m=0;m{"use strict";e.exports=function(e,t,n,r,o,a,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,o,a,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},4634:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},119:(e,t,n)=>{"use strict";n.r(t)},1043:(e,t,n)=>{"use strict";n.r(t)},5947:function(e,t,n){var r,o;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function o(e,t,n){return en?n:e}function a(e){return 100*(-1+e)}function i(e,t,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+a(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+a(e)+"%,0)"}:{"margin-left":a(e)+"%"}).transition="all "+t+"ms "+n,o}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=o(e,r.minimum,1),n.status=1===e?null:e;var a=n.render(!t),c=a.querySelector(r.barSelector),u=r.speed,d=r.easing;return a.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,i(e,u,d)),1===e?(s(a,{transition:"none",opacity:1}),a.offsetWidth,setTimeout((function(){s(a,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*o(Math.random()*t,.1,.95)),t=o(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var o,i=t.querySelector(r.barSelector),l=e?"-100":a(n.status||0),c=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(o=t.querySelector(r.spinnerSelector))&&p(o),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,o=e.length,a=t.charAt(0).toUpperCase()+t.slice(1);o--;)if((r=e[o]+a)in n)return r;return t}function o(e){return e=n(e),t[e]||(t[e]=r(e))}function a(e,t,n){t=o(t),e.style[t]=n}return function(e,t){var n,r,o=arguments;if(2==o.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&a(e,n,r);else a(e,o[1],o[2])}}();function c(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=f(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);c(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},5302:(e,t,n)=>{var r=n(4634);e.exports=p,e.exports.parse=a,e.exports.compile=function(e,t){return l(a(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=f;var o=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function a(e,t){for(var n,r=[],a=0,i=0,l="",u=t&&t.delimiter||"/";null!=(n=o.exec(e));){var d=n[0],f=n[1],p=n.index;if(l+=e.slice(i,p),i=p+d.length,f)l+=f[1];else{var g=e[i],h=n[2],m=n[3],y=n[4],b=n[5],v=n[6],w=n[7];l&&(r.push(l),l="");var k=null!=h&&null!=g&&g!==h,x="+"===v||"*"===v,S="?"===v||"*"===v,E=n[2]||u,_=y||b;r.push({name:m||a++,prefix:h||"",delimiter:E,optional:S,repeat:x,partial:k,asterisk:!!w,pattern:_?c(_):w?".*":"[^"+s(E)+"]+?"})}}return i{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,l=i.length;-1!==n.code.indexOf(o=t(r,l));)++l;return i[l]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=a.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=a[o],d=n.tokenStack[u],f="string"==typeof c?c:c.content,p=t(r,u),g=f.indexOf(p);if(g>-1){++o;var h=f.substring(0,g),m=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),y=f.substring(g+p.length),b=[];h&&b.push.apply(b,i([h])),b.push(m),y&&b.push.apply(b,i([y])),"string"==typeof c?l.splice.apply(l,[s,1].concat(b)):c.content=b}}else c.content&&i(c.content)}return l}(n.tokens)}}}})}(Prism)},3537:()=>{Prism.languages.solidity=Prism.languages.extend("clike",{"class-name":{pattern:/(\b(?:contract|enum|interface|library|new|struct|using)\s+)(?!\d)[\w$]+/,lookbehind:!0},keyword:/\b(?:_|anonymous|as|assembly|assert|break|calldata|case|constant|constructor|continue|contract|default|delete|do|else|emit|enum|event|external|for|from|function|if|import|indexed|inherited|interface|internal|is|let|library|mapping|memory|modifier|new|payable|pragma|private|public|pure|require|returns?|revert|selfdestruct|solidity|storage|struct|suicide|switch|this|throw|using|var|view|while)\b/,operator:/=>|->|:=|=:|\*\*|\+\+|--|\|\||&&|<<=?|>>=?|[-+*/%^&|<>!=]=?|[~?]/}),Prism.languages.insertBefore("solidity","keyword",{builtin:/\b(?:address|bool|byte|u?int(?:8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?|string|bytes(?:[1-9]|[12]\d|3[0-2])?)\b/}),Prism.languages.insertBefore("solidity","number",{version:{pattern:/([<>]=?|\^)\d+\.\d+\.\d+\b/,lookbehind:!0,alias:"number"}}),Prism.languages.sol=Prism.languages.solidity},3845:(e,t,n)=>{var r={"./prism-solidity":3537};function o(e){var t=a(e);return n(t)}function a(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}o.keys=function(){return Object.keys(r)},o.resolve=a,e.exports=o,o.id=3845},2694:(e,t,n)=>{"use strict";var r=n(6925);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},5556:(e,t,n)=>{e.exports=n(2694)()},6925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},2551:(e,t,n)=>{"use strict";var r=n(6540),o=n(9982);function a(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n