@abstract-foundation/agw-client
Version:
Abstract Global Wallet Client SDK
129 lines • 4.96 kB
JavaScript
import { concatHex, encodeFunctionData, } from "viem";
import { readContract, sendTransaction } from "viem/actions";
import { getAction, parseAccount } from "viem/utils";
import AGWAccountAbi from "../abis/AGWAccount.js";
import { SessionKeyValidatorAbi } from "../abis/SessionKeyValidator.js";
import { SESSION_KEY_VALIDATOR_ADDRESS } from "../constants.js";
import { AccountNotFoundError } from "../errors/account.js";
import { encodeSession } from "../sessions.js";
import { isSmartAccountDeployed } from "../utils.js";
/**
* Creates a session key for an Abstract Global Wallet.
*
* Session keys enable temporary, permissioned access to a wallet, allowing specific actions
* to be performed without requiring the wallet owner's signature for each transaction.
*
* @param args - Parameters for creating the session
* @param args.session - Session key configuration object
* @param args.paymaster - Optional address of a paymaster to sponsor the transaction
* @param args.paymasterInput - Optional data for the paymaster
* @returns Object containing the transaction hash of the session key creation and the session config
*
* @example
* ```ts
* import { useAbstractClient } from "@abstract-foundation/agw-react";
* import { LimitType } from "@abstract-foundation/agw-client/sessions";
* import { toFunctionSelector, parseEther } from "viem";
* import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
*
* // Generate a new session key pair
* const sessionPrivateKey = generatePrivateKey();
* const sessionSigner = privateKeyToAccount(sessionPrivateKey);
*
* export default function CreateSession() {
* const { data: agwClient } = useAbstractClient();
*
* async function createSession() {
* if (!agwClient) return;
*
* const { session } = await agwClient.createSession({
* session: {
* signer: sessionSigner.address,
* expiresAt: BigInt(Math.floor(Date.now() / 1000) + 60 * 60 * 24),
* feeLimit: {
* limitType: LimitType.Lifetime,
* limit: parseEther("1"),
* period: BigInt(0),
* },
* callPolicies: [
* {
* target: "0xC4822AbB9F05646A9Ce44EFa6dDcda0Bf45595AA",
* selector: toFunctionSelector("mint(address,uint256)"),
* valueLimit: {
* limitType: LimitType.Unlimited,
* limit: BigInt(0),
* period: BigInt(0),
* },
* maxValuePerUse: BigInt(0),
* constraints: [],
* }
* ],
* transferPolicies: [],
* },
* });
* }
*
* return <button onClick={createSession}>Create Session</button>;
* }
* ```
*
* @see {@link SessionConfig} - The session configuration type
* @see {@link encodeSession} - Function to encode a session configuration
*/
export async function createSession(client, args) {
const { account: account_ = client.account, chain = client.chain, session, ...rest } = args;
if (typeof account_ === "undefined")
throw new AccountNotFoundError({
docsPath: "/docs/actions/wallet/sendTransaction",
});
const account = parseAccount(account_);
const createSessionCall = await prepareCreateSessionCall(account, client, session);
const transactionHash = await getAction(client, sendTransaction, "sendTransaction")({
...createSessionCall,
...rest,
account: account,
chain: chain,
});
return { transactionHash, session };
}
export async function prepareCreateSessionCall(accountOrAddress, client, session) {
const account = parseAccount(accountOrAddress);
const isDeployed = await isSmartAccountDeployed(client, account.address);
const hasModule = isDeployed
? await hasSessionModule(account, client)
: false;
if (!hasModule) {
const encodedSession = encodeSession(session);
return {
to: account.address,
value: 0n,
data: encodeFunctionData({
abi: AGWAccountAbi,
functionName: "addModule",
args: [concatHex([SESSION_KEY_VALIDATOR_ADDRESS, encodedSession])],
}),
};
}
else {
return {
to: SESSION_KEY_VALIDATOR_ADDRESS,
value: 0n,
data: encodeFunctionData({
abi: SessionKeyValidatorAbi,
functionName: "createSession",
args: [session],
}),
};
}
}
async function hasSessionModule(account, client) {
const validationHooks = await getAction(client, readContract, "readContract")({
address: account.address,
abi: AGWAccountAbi,
functionName: "listHooks",
args: [true],
});
const hasSessionModule = validationHooks.some((hook) => hook === SESSION_KEY_VALIDATOR_ADDRESS);
return hasSessionModule;
}
//# sourceMappingURL=createSession.js.map