Wallet

On this page

The Gully Game SDK never holds a private key. Every write to Gully Chain (submitting a score, completing a quest, paying an x402 invoice) goes through one interface, ITransactionSender, that you implement with whatever account the player uses.

#The seam

C#
namespace GullyLabs.GameSdk
{
    public sealed class TransactionRequest
    {
        public string To;
        public string Data = "0x";
        public BigInteger Value = BigInteger.Zero;
        public long ChainId = GullyChain.TestnetChainId; // 485590
    }

    public interface ITransactionSender
    {
        string Address { get; }
        Task<string> SendTransactionAsync(TransactionRequest tx); // returns the tx hash once broadcast
    }
}

SDK methods that write take an ITransactionSender argument, for example GullyArcadeClient.SubmitScoreAsync(attestation, sender) and X402Client.GetAsync(url, sender). Methods that only build calldata (Erc20.TransferCalldata, Abi.Call) let you send it yourself.

#Which account backs it

Account When Notes
Player's Gully ID smart account default for Gully Studio games passkey-owned smart account (ZeroDev Kernel); the game acts through a session key with limited permissions; gas sponsored by the Gully Chain paymaster
Injected or external wallet WebGL builds, power users a thin bridge to the browser wallet
Server-side signer dedicated-server games that settle results themselves the key lives on the game server under Gully infrastructure rules, never in the client build

The player's address comes from the Gully ID gully_account claim (see Gully ID).

#Session keys

A passkey cannot sign silently mid-game. Instead, at sign-in the player approves a session key: a short-lived key, held by the game client, that the smart account accepts only for the calls and limits you request (for example: only submitScore on GullyArcade and complete on QuestRegistry, for 24 hours, with no value transfers). If the device is lost, the session expires on its own.

Coming soon

The SDK ships the ITransactionSender seam but no built-in Kernel session-key sender yet. Implement the interface against the Gully ID account stack, or use a server-side signer for testnet prototypes.

Gully accounts on Gully Chain have gas sponsored through the ERC-4337 paymaster, so players do not need ETH to play. The sender builds a user operation for the smart account and sends it to the Gully Chain bundler; the paymaster pays the fee.

#A minimal sender for testing

For editor tests against a local chain or a throwaway testnet key, a sender can sign raw transactions and post them with JsonRpcClient.SendRawTransactionAsync. Keep such keys out of the repo and out of builds.

C#
public sealed class DevSender : ITransactionSender
{
    readonly JsonRpcClient _rpc;
    readonly IMyTestSigner _signer;               // your own signing code, editor-only
    public DevSender(JsonRpcClient rpc, IMyTestSigner signer) { _rpc = rpc; _signer = signer; }
    public string Address => _signer.Address;
    public async Task<string> SendTransactionAsync(TransactionRequest tx)
    {
        string raw = await _signer.SignAsync(tx); // signed, RLP-encoded transaction hex
        return await _rpc.SendRawTransactionAsync(raw);
    }
}

#Rules

Heads up

Never put a private key, mnemonic or signer key in a game build, a repo, PlayerPrefs or a ScriptableObject. Anything shipped in a client can be extracted.

  • Request the narrowest session permissions that work, and the shortest lifetime.
  • Show the player what a transaction does before the first approval.
  • Link to the explorer after a write: GullyChain.TxUrl(txHash).