Auto-signing for apps
Requiring users to manually sign every transaction for every game is a terrible user experience not just because it breaks immersion constantly, but because it's incompatible with games where users play with a controller (which is how many users play games)
However, auto-signing can be dangerous. A game could steal all funds in your wallet without you explicitly approving it (either because the game was malicious, or because the game was hacked)
To tackle this, Paima introduces three different auto-sign methods that all guarantee safety of the user's L1 funds
1. Data-only auto-signing
For apps that run Paima batchers or similar systems (meta-transactions, account-abstraction or sequencers), signing data is often enough for the game
Concrete examples of cases where this is sufficient:
- Blockchains with zero transaction fees (Immutable, Oasys, etc.) where you can simply have somebody submit the transaction for you
- Systems where users pay to have free transactions (ex: deposit $5 into a contract, but have to "top up" their balance occasionally).
Namespaced auto-sign
For these cases, we just need to ensure that a message signed for one game cannot be reused for any other application (be it an L1 transaction or for a different game). Paima is great for this because every game/app gets its own L2 with its own data format, so messages are already unlikely to be reusable for other purposes
However, what if two apps use the same encoding for creating lobbies? It's very possible (especially if many projects for the same template), and so we may care to differentiate these.
To tackle this, Paima forces all games that want to use auto-sign to specify a security namespace
that guarantees signatures for their app are different than every other app. Notably, we recommend the following options for prefixes:
- The contract address
- A unique name. This is useful if your platform consists of multiple apps that you want to share the same auto-sign namespace
The format of these namespaces is namespace || rest
(learn more here). Paima Engine will not actually store these prefixes on-chain. Rather, it generates the signature sign(namespace || rest)
, but only posts the user command onchain. This is because the app knows its own prefix, so it can implicitly add the prefix to make sure the signature matches. This means even if a long string or contract address is used for the security namespace, it does not lead to chain bloat.
Defining your namespace
By default, the namespace is set to CONTRACT_ADDRESS
. However, there are cases where you may want to update your namespace. To do this, set the env variable SECURITY_NAMESPACE
to either
- A value (
SECURITY_NAMESPACE=foo
) - A YAML file (
SECURITY_NAMESPACE=namespace.yml
) with the following schema
The YAML configuration type allows you to specify multiple prefixes. This is useful in case you want your app to request a different auto-sign namespace depending on where it's deployed, but still treat signatures from other namespaces as valid. Note having many prefixes may have a performance impact due the cryptography overhead.
namespace:
write: "CONTRACT_ADDRESS"
read:
# Settings for block height >=10000
- block_height: 10000
prefix:
- "CONTRACT_ADDRESS" # Paima will replace this special keyword with your contract's address
- "company_name"
# Settings for block height >=15000
- block_height: 15000
prefix:
- "new_company_name"