# 設計 Paymaster 的注意事項

By [imToken Labs](https://paragraph.com/@imtoken-labs-2) · 2024-01-31

---

寫給開發者的 Account Abstraction（二）：設計 Paymaster 的注意事項
================================================

> *   作者：[Cyan](https://cyanho.medium.com/) @ imToken Labs
>     
> *   校對：Members at imToken Labs
>     
> *   封面來源：Image by [freepik](https://www.freepik.com/free-vector/hand-drawn-international-trade-with-coins_19962537.htm) on freepik
>     
> *   目標讀者：區塊鏈開發者
>     
> *   先備知識：
>     
>     *   熟悉智能合約開發
>         
>     *   知道抽象帳戶（Account Abstraction）的概念
>         
>     *   知道 [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) 的基本運作原理
>         
>     *   註：本篇文章介紹的 Paymaster 技術細節，都是基於 ERC-4337。
>         

* * *

**Paymaster 是什麼？**
------------------

Paymaster 主要的職責在於代替使用者支付交易上鏈的 gas 費用，只要能提供這樣的服務，我們就可以稱之為 Paymaster。事實上，Paymaster 並不是 AA（Account Abstraction）被提出後才出現的概念，早在 AA 之前，市場上已經有許多產品（例如 [Tokenlon](https://tokenlon.im/)）透過研發鏈下的 Relayer 服務，來協助使用者將交易上鏈，並且代替他們支付以原生代幣計價的 gas 費用，以提供更好的產品互動體驗。

![在鏈下代替使用者發送交易的 Relayer 服務，可以視為一種 Paymaster 實現。](https://storage.googleapis.com/papyrus_images/42dc43e57de53345572790e9c172b4bc8f9d9624cbdc23c8efadb469ddd18b67.png)

在鏈下代替使用者發送交易的 Relayer 服務，可以視為一種 Paymaster 實現。

但是，依賴於鏈下設施來提供 Paymaster 服務，會產生**服務商綁定**（**vendor lock-in**）的問題：

1.  如果慣用的 Paymaster 服務商，因為不可抗因素而停止運作，使用者會完全喪失 Paymaster 的功能，承受服務商單點故障的風險。
    
2.  各家 Paymaster 服務商會根據自己的業務需求，訂定出無法互相兼容的 API 規格，導致切換 Paymaster 服務商成本高昂。
    

![各家服務商提供的 API 規格不盡相同，使用者難以切換到不同的服務商。](https://storage.googleapis.com/papyrus_images/9e3c0a67256562e2cfa4d2a1910ca20c7114e55928702ca0c1125e0bc8d6612b.png)

各家服務商提供的 API 規格不盡相同，使用者難以切換到不同的服務商。

AA 和 ERC-4337（以下簡稱 4337）的出現，為我們帶來了兩個主要改變。

第一，4337 統一了在鏈下定義鏈上操作的資料結構，在 4337 提案裡稱之為 [UserOperation](https://eips.ethereum.org/EIPS/eip-4337#definitions)。鏈下資料結構有了統一的規範後，使用者可以降低對特定 Relayer 服務商的依賴，隨時切換到其他能夠處理 UserOperation 的 Relayer 服務。這些有能力處理 UserOperation 的 Relayer 服務，在 4337 提案裡稱之為 [Bundler](https://eips.ethereum.org/EIPS/eip-4337#definitions)。

第二，4337 在鏈上處理交易的流程中（可參考 [EntryPoint 合約](https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/core/EntryPoint.sol#L84-L113)），嵌入了 Paymaster 的抽象介面，讓 Paymaster 邏輯可以透過鏈上的智能合約實現，不只大幅降低了單點故障的風險，更開啟了鏈上可組合性的想像。

> 舉例來說，Paymaster 可以先代替使用者以原生代幣（例如 ETH）支付交易的 gas 費用，並在交易結束前，向使用者取回與代付原生代幣等值的 ERC-20 token（例如 USDT）。

![有了 4337 後，Paymaster 成為了鏈上永久存在的合約，透過鏈下統一的 UserOperation 資料結構，使用者可以隨時切換想使用的 Paymaster 服務。](https://storage.googleapis.com/papyrus_images/2bb1f793339782eeacb2eba575554a7ed5b781ab6738bbc8cef9300493b37fe8.png)

有了 4337 後，Paymaster 成為了鏈上永久存在的合約，透過鏈下統一的 UserOperation 資料結構，使用者可以隨時切換想使用的 Paymaster 服務。

總結來說，在 4337 之前，Paymaster 功能必須依賴於特定服務商所研發的鏈下 Relayer 服務；在 4337 之後，鏈下元件如 UserOperation 和 Bundler 有了統一的規範，Paymaster 變為純粹的鏈上智能合約，不只大幅降低了單點故障的風險，還能串接鏈上其他合約，實現更多元的應用場景。

**Paymaster 技術細節**
------------------

UserOperation 資料結構中，定義了一個給 Paymaster 使用的欄位 `paymasterAndData`：

    // UserOperation
    {
        ...
        paymasterAndData: <paymaster address (20 bytes)><custom data for paymaster>
    }
    

這個欄位前 20 bytes 為鏈上 Paymaster 合約的地址，使用者可以任意指定這筆交易想要使用哪個 Paymaster；在 20 bytes 的地址之後，可以附上任意長度的資料，視各個 Paymaster 合約需求來定義。特別注意的是，custom data 會直接接在 Paymaster 地址之後，以 Solidity 來說等同於：

    paymasterAndData = abi.encodePacked(paymasterAddress, customData)
    

在深入 Paymaster 運作流程之前，我們先來回顧一下 4337 的鏈下流程。首先，使用者會將交易的操作和意圖放入 UserOperation 資料結構裡；接著，使用者可以將 UserOperation 交給任意的 Bundler，請他們協助交易上鏈；最後，Bundler 會統一將 UserOperation 送至鏈上全局共享的 EntryPoint 合約，由 EntryPoint 合約在鏈上執行 AA 的交易處理流程。

![4337 鏈下流程](https://storage.googleapis.com/papyrus_images/4ce517fc3b0a02d12ef519874b6636a7288dd3307a33c9a9667f118edae34f1a.png)

4337 鏈下流程

UserOperation 進到 EntryPoint 合約後，是否使用 Paymaster 會有不同的交易流程。讓我們先來了解一下沒有使用 Paymaster 的流程，即 UserOperation `paymasterAndData` 欄位為空（`0x`）。

1.  EntryPoint 呼叫 Account 合約（地址由 UserOperation `sender` 欄位指定） `validateUserOp` 方法，來確認 Account 是否授權執行這筆 UserOperation。
    
2.  若 Account 授權同意，它必須自行支付這筆操作的 gas 費用給 EntryPoint。
    
3.  EntryPoint 檢查收到足夠的 gas 費用後，會接續呼叫 Account 的 `execute` 方法來執行 UserOperation 的交易內容。
    

![沒有使用 Paymaster 的交易流程，Account 必須自行支付 gas 費用。](https://storage.googleapis.com/papyrus_images/3d7e6c5585d73fe7ca5ee696bc8f6ae0df1697bcbc3088bcf390485e945243fd.png)

沒有使用 Paymaster 的交易流程，Account 必須自行支付 gas 費用。

當 UserOperation `paymasterAndData` 不為空時（`0x...`），EntryPoint 會改向 Paymaster 索取 gas 費用。

1.  EntryPoint 呼叫 Account `validateUserOp` 來驗證 UserOperation 的合法性。
    
2.  EntryPoint 會從 `paymasterAndData` 前 20 bytes 拿出 Paymaster 地址，呼叫 Paymaster `validatePaymasterUserOp` 來確認 Paymaster 是否願意為這筆 UserOperation 支付 gas 費用。
    
3.  若 Paymaster 授權同意，Paymaster 會代替 Account 支付這筆操作的 gas 費用給 EntryPoint。
    
4.  EntryPoint 檢查收到足夠的 gas 費用後，會接續呼叫 Account 的 `execute` 方法來執行 UserOperation 的交易內容。
    
5.  EntryPoint 會呼叫 Paymaster `postOp` 方法，Paymaster 可以利用這個方法，在 Account 操作執行完成後，進行額外的後續動作。（例如：等 Account 完成 swap 操作後，要求以等值的 USDT 來償還 Paymaster 在第 3 步驟事先代墊的 gas 費用。）
    

![使用 Paymaster 的交易流程，Paymaster 會代替 Account 支付 gas 費用。](https://storage.googleapis.com/papyrus_images/df6484e2862137ac46e552a5a73879142f8a7b242fd2e72bb7fc64b36f93465f.png)

使用 Paymaster 的交易流程，Paymaster 會代替 Account 支付 gas 費用。

4337 在鏈上將 Paymaster 抽象成一個通用的介面，只要有實作這個介面（如下圖所示），合約就可以被當成 Paymaster 來使用。

> 事實上，只有 `validatePaymasterUserOp` 是一定要實作的方法，如果不需要在 Account 操作結束後，執行額外的動作，可以完全略過 `postOp` 的實作。（[example](https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/samples/VerifyingPaymaster.sol)）

![Paymaster 合約介面](https://storage.googleapis.com/papyrus_images/230a13428aa6c8a5d9179961f32fa67d216dea25ede8ffc1b95b06d744ec5587.png)

Paymaster 合約介面

實作這兩個方法時，有一些重要的事情必須注意：

*   `validatePaymasterUserOp`
    
    *   不能存取任何會隨區塊變動的資訊，例如 `block.number`、`block.timestamp`。
        
    *   只能存取與 Account 地址相關的 storage，詳細規則可以[參考這裡](https://eips.ethereum.org/EIPS/eip-4337#storage-associated-with-an-address)。
        
    *   若 Paymaster 需要進行下列動作時，需要事先在 EntryPoint 上進行 [stake](https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/core/StakeManager.sol#L55-L75)，stake 所需數量會由處理 UserOperation 的 Bundler 決定。（以 [eth-infinitism/bundler](https://github.com/eth-infinitism/bundler) 實作為例，stake 所需數量由[啟動時的參數設定](https://github.com/eth-infinitism/bundler/blob/main/packages/bundler/localconfig/bundler.config.json#L10)）
        
        *   存取 Paymaster 自身合約的 storage 以及其他合約上與 Paymaster 地址相關的 storage，詳細規則可以[參考這裡](https://eips.ethereum.org/EIPS/eip-4337#storage-associated-with-an-address)。
            
        *   `validatePaymasterUserOp` 回傳非空的 `context`，使 EntryPoint 觸發 `postOp` 函式；換句話說，也就是需要使用到 `postOp` 的功能時，就需要 stake。
            
*   `postOp`
    
    *   沒有 validate 階段的限制，可以執行任何操作。
        
    *   `validatePaymasterUserOp` 第一個回傳參數 `context` 必須不為空（`context.length > 0`），否則 EntryPoint 會直接略過 `postOp` 。
        

> `validatePaymasterUserOp` 和 `postOp` 考量到安全性，建議只開放給 EntryPoint 呼叫，可參考官方合約 [BasePaymaster](https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/core/BasePaymaster.sol#L28) 的實作。

在 validate 階段會有這麼多限制的原因，主要是為了保護 Bundler。Bundler 在收到 UserOperation 時會先做一次模擬，確保 UserOperation 上鏈後能順利執行；在模擬完成後，Bundler 會先將 UserOperation 放進 mempool，繼續收集其他 UserOperation；直到特定的條件達成後，例如 mempool 裡 UserOperation 的數量、距離上一次 bundle 發送的時間間隔等等，Bundler 才會將這段期間內收集的多筆 UserOperation，打包成一個 bundle，在同一筆交易裡送給 EntryPoint。

因此，UserOperation 被 Bundler 收錄，到實際上鏈之間，會有浮動的時間差存在，若 validate 階段允許存取會隨區塊變動的資訊，UserOperation 有可能在最初的模擬時驗證成功，卻在最後上鏈時驗證失敗，導致 Bundler 蒙受損失。

> 更多細節可以參考下週發布的 Bundler 文章。

在本小節最後，再多分享一些實作 Paymaster 時必須特別留心的事項給開發者們：

*   Paymaster 必須事先 [deposit](https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/core/StakeManager.sol#L46-L53) 足夠的 gas 費用到 EntryPoint 上，幫忙 Account 支付的 gas 費用會直接從 deposit balance 中扣除。
    
    *   Paymaster 不能像 Account 一樣，在 validate 階段動態支付 gas 費用給 EntryPoint
        
*   若 `postOp` 執行時發生 revert，EntryPoint 會將鏈上 state revert 回 validate 剛完成的時候，然後再重新呼叫一次 `postOp`；若第二次 `postOp` 還是被 revert，則整個 bundle 會被 revert。
    
    *   背後的構想是，Paymaster 在 validate 階段驗證 Account 擁有足夠的 token balance，但是 Account 有可能在 execute 階段將所有 token 轉移出去，造成 Paymaster 在 `postOp` 裡無法向 Account 索取預期的 token 數量而導致 revert。因此，EntryPoint 若能將 state revert 回 validate 階段剛驗證完 Account 擁有足夠的 token balance 時，就可以確保第二次 `postOp` 通過。
        
    *   特別注意的是，在即將推出的 EntryPoint 0.7 版本中，[這個機制會被移除](https://github.com/eth-infinitism/account-abstraction/pull/311)，會帶來以下的改變：
        
        *   EntryPoint 最多只會執行一次 `postOp`，且 `postOp` revert 不會導致整個 bundle revert，而是改為 [emit event](https://github.com/eth-infinitism/account-abstraction/blob/87287cc1178acda61dbd41119bd841eeb8d7c2ca/contracts/core/EntryPoint.sol#L127-L132)。
            
            *   這個改變降低了 Bundler 被 Paymaster 搗亂的風險，但是相對的卻會增加 Paymaster 在 `postOp` 收不到款項的風險。在未來，Paymaster 透過 `validatePaymasterUserOp` 事先向 Account 收取費用，可能會是比較保險的做法。
                
        *   Paymaster `postOp` 實作邏輯變單純，不需要考慮到有可能被呼叫兩次的情況。
            
        *   使用 Paymaster 時的 verificationGasLimit 可以降低，[預留的乘數從 3 倍降為 2 倍](https://github.com/eth-infinitism/account-abstraction/blob/d140003b96936a6b7c8dba609746690820b1d4f0/contracts/core/EntryPoint.sol#L343)，減少 prefund gas 的數目。
            
*   Bundler 會有特定的演算法，來計算 Paymaster 的評分（reputation）。
    
    *   Paymaster revert 時會導致整個 bundle 交易失敗，使 Bundler 遭受損失。若 Paymaster revert 頻率很高，Bundler 會懷疑這個 Paymaster 可能帶有惡意，藉此調降其評分。當評分過低時，Bundler 甚至會完全禁止接受與該 Paymaster 有關的 UserOperation。
        

**Paymaster 設計範例**
------------------

在這一小節裡，我會整理出近期市場上已經在使用的幾種 Paymaster 實作範例，開發者在設計 Paymaster 時可以當作參考。我大致上將這些實作分成四種類別，為了方便討論，我簡略地為這些類別取了個名字，但是這些名字還不是業內共識，使用上請多加留意。

### **Permissioned Paymaster**

Permissioned Paymaster 設計原理很單純，Paymaster 合約身上可以事先記錄特定一組 admin 地址，只要 UserOperation `paymasterAndData` 裡有包含 admin 對這筆 UserOperation hash 的簽名，就會為這筆 UserOperation 支付 gas 費用。

這類型的 Paymaster 服務如 [Pimlico Verifying Paymaster](https://polygonscan.com/address/0x984e2abb41a6684e5e213ab61ad4c6c830585df9#code)（[doc](https://docs.pimlico.io/permissionless/tutorial/tutorial-1#request-pimlico-verifying-paymaster-sponsorship)），需要在鏈下串接服務商的 API，只要能從鏈下後端服務取得 admin 的授權簽名，鏈上 Paymaster 合約就會贊助使用者 UserOperation 的 gas 費用。

*   `validateUserOp`
    
    *   驗證 `paymasterAndData` 中是否包含 admin 簽名。
        
*   `postOp`
    
    *   無任何動作
        

完整應用流程如下：

1.  服務商設定一組 admin 地址到 Paymaster 合約上。
    
2.  使用者透過服務商鏈下的 Paymaster Service，獲取 `paymasterAndData`，其中會包含 admin 對 UserOperation hash 的簽名。
    
3.  使用者將 `paymasterAndData` 放入 UserOperation，送給 Bundler。
    
4.  `validatePaymasterUserOp` 檢查 `paymasterAndData` 裡是否包含 admin 對 UserOperation hash 的簽名。
    
    1.  若有，則為該筆操作支付 gas 費用。
        
    2.  若無，則拒絕支付。
        

![Permissioned Paymaster Flow](https://storage.googleapis.com/papyrus_images/423699ff21becace269dc90751d82a3feb651fe2eaf09f2b539798fb7777e4ab.png)

Permissioned Paymaster Flow

儘管取得 admin 簽名後，鏈上 Paymaster 合約會直接贊助 UserOperation 並不額外收取費用，但是服務商的鏈下後端服務，可以設計額外的機制，例如使用者必須事先儲值足夠的金額，後端服務才會給你 admin 的授權簽名。

> 依照業務需求，Permissioned Paymaster 也可以在合約裡向 Account 收取服務費用。

### **Accounting Paymaster**

Accounting Paymaster 會在合約上記錄每個使用者的餘額，使用者在運用 Paymaster 服務前，需要事先儲值足夠的金額至 Paymaster 合約，當 Paymaster 為使用者的 UserOperation 預付以原生代幣計價的 gas 費用後，會再從使用者儲值在合約上的餘額，取回服務的費用。

> 這裡提到的餘額，不一定要是 ETH，可以根據業務需求，要求使用者儲值不同的幣種到合約上。

這類型的 Paymaster 服務如 [Biconomy Paymaster](https://polygonscan.com/address/0x000031dd6d9d3a133e663660b959162870d755d4#code)（[doc](https://docs.biconomy.io/dashboard)），需要在鏈下透過他們的 Dashboard 來事先儲值 ETH 至 Paymaster 合約上；除此之外，Biconomy Paymaster 同時也套用了 Permissioned Paymaster 的設計模式，需要特定的 admin 簽名才可以使用他們鏈上的 Paymaster 服務。

*   `validateUserOp`
    
    *   驗證 `paymasterAndData` 中是否包含 admin 簽名。
        
    *   驗證使用者在合約上是否有足夠的儲值金。
        
*   `postOp`
    
    *   從使用者在合約上的儲值金取回代墊的 gas 費用。
        

完整應用流程如下：

1.  服務商設定一組 admin 地址到 Paymaster 合約上。
    
2.  使用者透過服務商鏈下 Paymaster Service，儲值金額至 Paymaster 合約。
    
3.  使用者透過服務商鏈下的 Paymaster Service，獲取 `paymasterAndData`，其中會包含 admin 對 UserOperation hash 的簽名。
    
4.  使用者將 `paymasterAndData` 放入 UserOperation，送給 Bundler。
    
5.  `validatePaymasterUserOp` 檢查 `paymasterAndData` 裡是否包含 admin 對 UserOperation hash 的簽名，並且檢查使用者在合約上是否有足夠的儲值金。
    
6.  `postOp` 從使用者在合約上的儲值金，取回代墊的 gas 費用。
    

![Accounting Paymaster Flow](https://storage.googleapis.com/papyrus_images/a81a123f4273568dd642d7783e37e1ee73e570f87f8428f7d2b32c463c77a83d.png)

Accounting Paymaster Flow

Accounting Paymaster 有幾種應用情境，例如 DApp 項目方可以預先儲值足夠的金額至 Paymaster 合約上，來獎勵 DApp 使用者可以進行免手續費的操作；或是在合約上接受儲值不同的幣種，來達成以其他幣種支付 gas 費用的效果。

### **Off-chain Oracle Paymaster**

Off-chain Oracle Paymaster 會依據鏈下的報價資訊，讓使用者能透過不同的 token 來支付 gas 費用。這個設計需要仰賴一組特定的 oracle owner 地址，來讓 Paymaster 合約確保報價來源的合法性；除此之外，使用者必須事先授權 token allowance 給 Paymaster 合約，Paymaster 合約才能在交易的最後從 Account 身上轉回與代墊 gas 費用等值的 token。

這類型的 Paymaster 服務如 [Stackup Paymaster](https://polygonscan.com/address/0xe93eca6595fe94091dc1af46aac2a8b5d7990770#code)（[doc](https://docs.stackup.sh/docs/paymaster-api)）、[Candide Paymaster](https://github.com/candidelabs/CandideWalletContracts/blob/main/contracts/paymaster/CandidePaymaster.sol)，服務商需要在鏈下提供額外的報價服務。只要兌換率是服務商可以接受的，誰來使用 Paymaster 服務差異並不大，因此相較於 Permissioned Paymaster，Off-chain Oracle Paymaster 是更開放的設計模式。

*   `validateUserOp`
    
    *   驗證 `paymasterAndData` 中的報價資訊，是否經過 oracle owner 簽名授權。
        
    *   根據鏈下報價資訊，驗證 Account 是否有足夠的 token 支付 gas 費用。
        
*   `postOp`
    
    *   根據鏈下報價資訊，計算與 gas 費用等值的 token 數量。
        
    *   從 Account 身上取回該數量的 token。
        

> 由於 validate 階段有諸多的限制，例如無法存取鏈上 Oracle 的 storage，因此才需要從鏈下提供報價。

完整應用流程如下：

1.  服務商設定一組 oracle owner 地址到 Paymaster 合約上。
    
2.  使用者透過服務商鏈下的 Paymaster Service，獲取 `paymasterAndData`，其中會包含報價資訊以及 oracle owner 對報價的簽名。
    
3.  使用者將 `paymasterAndData` 放入 UserOperation，送給 Bundler。
    
4.  `validatePaymasterUserOp` 檢查 `paymasterAndData` 裡的報價資訊，是否經過 oracle owner 授權簽名，並且依據報價資訊，檢查 Account 是否有足夠的 token 支付 gas 費用。
    
5.  `postOp` 根據鏈下報價資訊，計算與 gas 費用等值的 token 數量，向 Account 索取。
    

![Off-chain Oracle Paymaster Flow](https://storage.googleapis.com/papyrus_images/410b12261afe5e80d6deb300ca592ed130f206fc8f6a584f5b4815bde6c78e2e.png)

Off-chain Oracle Paymaster Flow

### **On-chain Oracle Paymaster**

On-chain Oracle Paymaster 會根據鏈上的報價資訊，讓使用者能透過不同的 token 來支付 gas 費用。這種設計模式完全不需仰賴任何鏈下服務，實現了無准入的去中心化理想，但是換來的是 Paymaster 合約實作的複雜性。

先前有提到因為 validate 階段的限制，導致 Paymaster 不能存取到鏈上 Oracle 的 storage，所以無法在鏈上取得報價。但是 On-chain Oracle Paymaster 這個設計模式巧妙地繞過了這個限制，透過在 Paymaster 合約上緩存過去的報價資訊， `validatePaymasterUserOp` 只需要存取到 Paymaster 合約本身的 storage，就可以取得參考的報價，並且利用沒有 storage 存取限制的 `postOp`，去向鏈上 Oracle 更新這份報價的緩存，來計算使用者最後需要支付的 token 數量。

這類型的 Paymaster 服務如 [Pimlico ERC20 Paymaster](https://github.com/pimlicolabs/erc20-paymaster-contracts/blob/master/src/PimlicoERC20Paymaster.sol)，只需要部署 Paymaster 合約就可以提供服務。但是對服務商來說，還是需要不定時到 EntryPoint 上補充 Paymaster 合約的餘額，並且定期檢查合約上緩存的報價，是否已經偏離市場太多，必要時需要以手動的方式來更新緩存的報價。

*   `validateUserOp`
    
    *   透過合約內過去的緩存報價，驗證 Account 是否有足夠的 token（視情況加上額外的 buffer）支付 gas 費用。
        
    *   提前向 Account 索取 token。
        

> 由於 validate 階段使用的報價為過去的緩存，為了避免短時間內價格大幅波動，所以收取了額外的 buffer 以減少 Paymaster 虧損的可能性。

*   `postOp`
    
    *   向鏈上 Oracle 取得最新的報價資訊，更新合約上的緩存。
        
    *   根據最新的報價資訊，計算 Account 實際需要支付的 token 數量。
        
    *   若在 validate 階段有超額收取，則退回多出來的部份給 Account。
        

完整應用流程如下：

1.  使用者根據 Paymaster 合約介面，自行組建 `paymasterAndData` 放入 UserOperation，送給 Bundler。
    
2.  `validatePaymasterUserOp` 根據緩存的報價，加上額外的 buffer 避免價格波動的風險，驗證 Account 身上是否有足夠的 token 支付 gas 費用，提前向 Account 索取 token。
    
3.  `postOp` 向鏈上 Oracle 取得最新報價，更新 Paymaster 合約上的緩存，並計算 Account 實際需要支付的 token 數量。
    
    1.  若在 validate 階段有超額收取，則退回多出來的部份給 Account。
        

![On-chain Oracle Paymaster Flow](https://storage.googleapis.com/papyrus_images/3a925526d6a69f8221b2f6cca630d6a90ee36a1c4d8cb620a59e714344a7e4f9.png)

On-chain Oracle Paymaster Flow

**Paymaster 市場數據**
------------------

目前 4337 最被廣泛使用在 Polygon 上，因此接下來的市場數據會以 Polygon 為主。

> 數據與圖表來源：[ERC-4337 Smart Accounts](https://dune.com/niftytable/account-abstraction)

![Paymaster Market Share](https://storage.googleapis.com/papyrus_images/940ca159339dcfaa6772c5e4380c6604f7020f1f0d058236fcbb44f74a8d3eb7.png)

Paymaster Market Share

截至 2023/12 月，Paymaster 市佔前三名分別是 Plimlico、Biconomy 和 Alchemy，其中 Pimlico 為先前介紹的 [Pimlico Verifying Paymaster](https://polygonscan.com/address/0x984e2abb41a6684e5e213ab61ad4c6c830585df9#code)（Permissioned Paymaster），Biconomy 為先前介紹的 [Biconomy Paymaster](https://polygonscan.com/address/0x000031dd6d9d3a133e663660b959162870d755d4#code)（Accounting Paymaster）。比較會令開發者感到意外的是，去中心化的 [Pimlico ERC20 Paymaster](https://github.com/pimlicolabs/erc20-paymaster-contracts/blob/master/src/PimlicoERC20Paymaster.sol)（On-chain Oracle Paymaster） 方案事實上沒有多少人在使用，合理的猜測可能是各家廠商的產品，可以透過中心化授權的方案，直接給予使用者交易費上的優惠。

![Successful UserOperation Count](https://storage.googleapis.com/papyrus_images/a8022f5e9bd481eddd0cfb58d257fba175288c9619a71e4cd48c7dafbd05edde.png)

Successful UserOperation Count

![Gas Covered by Paymasters](https://storage.googleapis.com/papyrus_images/90f8eeeb444e9c4e64262f3195e36304601f5e00b6eaa0aa4914ccd4f300d7e6.png)

Gas Covered by Paymasters

雖然原始數據中，無法得知 UserOperation 使用 Paymaster 的比例，但是從上面兩張圖表可以觀察到，UserOperation 數量與 Paymaster 贊助的 gas 量大致上呈現正相關，藉此可以推測出有一定比例的 UserOperation 持續在使用 Paymaster。

**References**
--------------

*   [ERC-4337: Account Abstraction Using Alt Mempool](https://eips.ethereum.org/EIPS/eip-4337)
    
*   [GitHub - eth-infinitism/account-abstraction at abff2aca61a8f0934e533d0d352978055fddbd96](https://github.com/eth-infinitism/account-abstraction/tree/abff2aca61a8f0934e533d0d352978055fddbd96)
    
*   [GitHub - consenlabs/ethtaipei2023-aa-workshop: Account abstraction workshop @ ETHTaipei 2023](https://github.com/consenlabs/ethtaipei2023-aa-workshop)
    
*   [ERC-4337 Smart Accounts](https://dune.com/niftytable/account-abstraction)
    
*   2023 Dapp Learning AA Introduction by imToken
    
    *   Part 1（Overview + Account）：[YouTube](https://www.youtube.com/watch?v=F2AWai-A0Ng)、[Bilibili](https://www.bilibili.com/video/BV1Mb4y137qZ/)
        
    *   Part 2（Paymaster + Bundler）：[YouTube](https://www.youtube.com/watch?v=xJiGoWSaGpA) 、[Bilibili](https://www.bilibili.com/video/BV1Qe41167db/)
        
    *   Paymaster 投影片：[DApp Learning Paymaster](https://docs.google.com/presentation/d/1RCZMrT_xncU7IClcLnHwmq6bABTS1OI0BIfez4g7rPQ/edit?usp=sharing)

---

*Originally published on [imToken Labs](https://paragraph.com/@imtoken-labs-2/paymaster)*
