Skip to content

Instantly share code, notes, and snippets.

@EnoF
Last active November 13, 2024 13:58
Show Gist options
  • Select an option

  • Save EnoF/2b51a5268280fe584a657140d4e44de7 to your computer and use it in GitHub Desktop.

Select an option

Save EnoF/2b51a5268280fe584a657140d4e44de7 to your computer and use it in GitHub Desktop.
Gas Stations

Gas Stations

A gas station is a coin account that pays for gas fees on behalf of a user. Let's explore how we can create an account that is scoped to only pay for gas for specific transactions.

Unscoped Gas Station

To start off, let's create a gas station that is unscoped. From there we can then see how we can scope it to only pay for gas for specific transactions.

(namespace 'free)
(module test G
  (defcap G() true)
  (defun allow() true)
)

(let ((guard (create-user-guard (test.allow))))
  (coin.create-account (create-principal guard) guard)
)

In this example, we create a gas station account that is unscoped. This means account will pay for anything, even for transfers.

Unscoped Gas Station with Capability guard

Before we move to scoping the gas station, we will migrate the above code to make use of a capability guard. This allows us to have more control over the guard that we want to use and grant data-base access.

(namespace 'free)
(module test G
  (defcap G() true)
  (defcap ALLOW() true)
)

(let ((guard (create-capability-guard (test.ALLOW))))
  (coin.create-account (create-principal guard) guard)
)

Scope to GAS_PAYMENTS

Now we can change the module we created to scope it to only pay for gas fees. To do so, we must implement the gas-payer-v1 interface.

(namespace 'free)
(module test G
  (defcap G() true)

  (implements gas-payer-v1)
  (defcap ALLOW:bool() true)
  (defcap GAS_PAYER:bool
    ( user  : string
      limit : integer
      price : decimal
    )
    (compose-capability (ALLOW))
  )
  (defun create-gas-payer-guard:guard()
    (create-capability-guard (test.ALLOW))
  )
)

(let ((guard (free.test.create-gas-payer-guard)))
  (coin.create-account (create-principal guard) guard)
)

With this change, we tell chainweb that this account is eligible to pay for paying gas fees if GAS_PAYER capability is granted. Since the GAS_PAYER capability is always passing, that means that this gas-station will pay for any transaction's gas fees.

Scope to specific transactions

Now that we have a gas station that is scoped to pay for gas fees, we can further scope it to only pay for gas fees for specific transactions. In the following example we scope the gas station to only pay for gas fees for transactions that have a gas price less than 0.00000001, but the owner of free.some-admin-keyset can use this gas station to pay for any transaction.

(namespace 'free)
(module test G
  (defcap G() true)

  (implements gas-payer-v1)
  (defcap ALLOW:bool() true)
  (defcap GAS_PAYER:bool
    ( user  : string
      limit : integer
      price : decimal
    )
    (enforce-one
      "Allow admin to use this gas station for any transaction"
      [
        (enforce-guard "free.some-admin-keyset")
        (enforce (<= 0.00000001 (at 'gas-price (chain-data)))
          "Gas price must be less than 0.00000001"
        )
      ]
    )
    (compose-capability (ALLOW))
  )
  (defun create-gas-payer-guard:guard()
    (create-capability-guard (test.ALLOW))
  )
)

(let ((guard (free.test.create-gas-payer-guard)))
  (coin.create-account (create-principal guard) guard)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment