0.0.9 • Published 9 months ago

@braavosdev/session-keys v0.0.9

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

Braavos Session Keys

Motivation

The Braavos session keys feature allows dapps to request the wallet to grant permissions to execute transactions in the user's behalf without prompting them for each transaction. This library interacts with Braavos wallets which support this feature.

Installation

To add this package to your project run npm install @braavosdev/session-keys --add

Gas sponsored sessions

Gas sponsored sessions are sessions in which transactions are sent in the name of the user, but fees are paid by the dapp account. This mechanism is based on SNIP-9 Outside execution "from outside".

Signing the session request

To use this feature a dapp must first ask the user to connect their wallet and sign a message. This can be done with the following function:

signGasSponsoredSessionRequest = async (
    account: AccountInterface,
    request: GasSponsoredSessionSignatureRequest
): Promise<Signature>;

Where account is the connected user account and the type GasSponsoredSessionSignatureRequest contains the following properties:

type GasSponsoredSessionSignatureRequest = {
    callerAddress: string;
    executeAfter: Date;
    executeBefore: Date;
    requestedMethods: RequestedMethod[];
    spendingLimits: SpendingLimit[];
};

type RequestedMethod = {
    contractAddress: string;
    entrypoint: string;
};

type SpendingLimit = {
    tokenAddress: string;
    amount: Uint256;
};

The properties of this type are: 1. callerAddress - address of the dapp account which will be performing the "transactions from outside" and paying the fees 2. executeAfter - date after which the session is valid 3. executeBefore - date after which the session is expired 4. requestedMethods - array of pairs of contract addresses and entrypoints which the dapp account may call in the context of this session 5. spendingLimits - array of erc-20 token addresses which the account contract will track and limit their transfers and approval to the given amount

Executing gas sponsored session transactions

Once the signature is obtained and the execute_after time had passed the dapp account may execute transactions in the context of the session in the name of the user. To generate a gas sponsored transaction the following function can be used:

getGasSponsoredSessionTx = async (
    request: GasSponsoredSessionTransactionRequest
): Promise<Call>;

Where GasSponsoredSessionTransactionRequest contains the following properties:

type GasSponsoredSessionTransactionRequest = {
    callerAddress: string;
    executeAfter: Date;
    executeBefore: Date;
    requestedMethods: RequestedMethod[];
    spendingLimits: SpendingLimit[];
    sessionAccountAddress: string;
    calls: Call[];
};

The following attributes must be identical to those given when requesting signature: 1. callerAddress 2. executeAfter 3. executeBefore 4. requestedMethods 5. spendingLimits

sessionAccountAddress should be the user account address and calls is the list of calls the dapp would like to execute.

Example

The following snippet requests the user to sign on a gas sponsored session:

    const sessionGSRequest = {
        callerAddress: "0x01bf914fef319eb1cc2769100f817fbbdd99be01b1e20daa45ab031dee3ef14b",
        sessionAccountAddress: sessionAccountAddress,
        executeAfter: new Date(0),
        executeBefore: new Date(1756299408),
        requestedMethods: [
            {
                contractAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                entrypoint: "transfer",
            },
            {
                contractAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                entrypoint: "approve",
            },
            {
                contractAddress:
                    "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
                entrypoint: "transfer",
            },
            {
                contractAddress:
                    "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
                entrypoint: "approve",
            },
        ],
        spendingLimits: [
            {
                tokenAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                amount: { low: 100, high: 0 },
            },
        ],
    };
    const wallet = await getStarknet().getLastConnectedWallet();
    if (wallet?.isConnected) {
        signature = await signGasSponsoredSessionRequest(
            wallet.account,
            sessionGSRequest
        );
    }

After this message is signed, the callerAddress can send transactions "from outside" which comply with the requestedMethods list and may spend up to 0.001 ETH.

The following snippet sends a transaction in the context of this session:

    import { getGasSponsoredSessionTx } from "@braavosdev/session-keys";
    const res = await getGasSponsoredSessionTx({
        calls: [
            {
                contractAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                entrypoint: "transfer",
                calldata: [
                    "0x01bf914fef319eb1cc2769100f817fbbdd99be01b1e20daa45ab031dee3ef14b",
                    1,
                    0,
                ],
            },
            {
                contractAddress:
                    "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
                entrypoint: "approve",
                calldata: [
                    "0x01bf914fef319eb1cc2769100f817fbbdd99be01b1e20daa45ab031dee3ef14b",
                    200,
                    0,
                ],
            },
        ],
        ...sessionGSRequest,
        gsSessionSignature: signature!,
    });
    const txres = await dappAccount.execute(res);

This transaction contains to calls that will be executed in the name of sessionAccountAddress

Non gas sponsored sessions

After a user signs the session request for a non gas sponsored sessions a dapp may trigger transactions in the name of the user account. To start a non gas sponsored session a dapp needs to call the following library function to generate a session account object (implementing the starknet-js AccountInterface) which can execute transactions in the name of the user account without prompting the wallet:

requestSessionAccount = async (
    provider: ProviderInterface,
    account: AccountInterface,
    request: SessionAccountRequest
): Promise<SessionAccount>;

Where SessionAccountRequest contains the following properties

type SessionAccountRequest = {
    executeAfter: Date;
    executeBefore: Date;
    requestedMethods: RequestedMethod[];
    spendingLimits: SpendingLimit[];
    ethGasLimit: u128;
    strkGasLimit: u128;
}

The two fields ethGasLimit and strkGasLimit set an upper bound to the amount of fees the user account may spend in this session.

Example

The following code requests the user to sign on a non gas sponsored session:

    import {
        signGasSponsoredSessionRequest,
        getGasSponsoredSessionTx,
        requestSessionAccount,
    } from "@braavosdev/session-keys";

    const sessionRequest = {
        executeAfter: new Date(0),
        executeBefore: new Date(1756299409),
        ethGasLimit: "1000000000000000000",
        strkGasLimit: "1000000000000000000",
        requestedMethods: [
            {
                contractAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                entrypoint: "transfer",
            },
            {
                contractAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                entrypoint: "approve",
            },
            {
                contractAddress:
                    "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
                entrypoint: "transfer",
            },
            {
                contractAddress:
                    "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
                entrypoint: "approve",
            },
        ],
        spendingLimits: [
            {
                tokenAddress:
                    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
                amount: { low: 100, high: 0 },
            },
        ],
    };

    const wallet = await getStarknet().getLastConnectedWallet();
    if (wallet?.isConnected) {
        const sessionAccount = await requestSessionAccount(
            wallet.provider,
            wallet.account,
            sessionRequest
        );
    }

requestSessionAccount will prompt the user to sign the session request. Once signed the dapp may use sessionAccount.execute(..) to execute transactions in the context of the session.

0.0.9

9 months ago

0.0.8

9 months ago

0.0.5

9 months ago

0.0.7

9 months ago

0.0.6

9 months ago

0.0.4

9 months ago

0.0.3

9 months ago

0.0.2

9 months ago

0.0.1

9 months ago