EcosystemWallet.CreateSessionKey
Creates a session key for the user wallet with EIP-7702 functionality. Session keys allow delegated access to the wallet with specific permissions and time constraints. This method is only supported for EIP7702 and EIP7702Sponsored execution modes.
How it works: The method creates a SessionSpec
with your parameters, signs it using EIP-712, and calls createSessionWithSig
on the EIP-7702 account contract to register the session key on-chain.
// Create a session key for 24 hours with full permissionsvar receipt = await ecosystemWallet.CreateSessionKey(chainId: 1,signerAddress: await sessionSigner.GetAddress(),durationInSeconds: 86400, // 24 hoursgrantFullPermissions: true);// Create a session key with specific call and transfer policiesvar callPolicies = new List<CallSpec>{new CallSpec{Target = "0x1234567890123456789012345678901234567890",Selector = new byte[] { 0xa9, 0x05, 0x9c, 0xbb }, // transfer(address,uint256)MaxValuePerUse = BigInteger.Parse("100000000000000000"), // 0.1 ETH max per callValueLimit = new UsageLimit{LimitType = 1, // Lifetime limitLimit = BigInteger.Parse("1000000000000000000"), // 1 ETH totalPeriod = 86400 // 1 day period},Constraints = new List<Constraint>{new Constraint{Condition = 1, // Equal to (not 0)Index = 0, // First parameter (to address)RefValue = new byte[32], // Reference value for validationLimit = new UsageLimit{LimitType = 2, // Allowance (not 0)Limit = BigInteger.Parse("500000000000000000"), // 0.5 ETH per periodPeriod = 3600 // 1 hour}}}}};var transferPolicies = new List<TransferSpec>{new TransferSpec{Target = "0x0000000000000000000000000000000000000000", // ETH transfersMaxValuePerUse = BigInteger.Parse("100000000000000000"), // 0.1 ETH max per transferValueLimit = new UsageLimit{LimitType = 1, // Lifetime limitLimit = BigInteger.Parse("1000000000000000000"), // 1 ETH totalPeriod = 86400 // 1 day}},new TransferSpec{Target = "0xA0b86a33E6411a3bb4CC4C7b9C5C5C7C7C8C9C0c", // Specific token contractMaxValuePerUse = BigInteger.Parse("1000000000000000000000"), // 1000 tokens max per transferValueLimit = new UsageLimit{LimitType = 2, // Allowance (resets every period)Limit = BigInteger.Parse("10000000000000000000000"), // 10,000 tokens per periodPeriod = 3600 // 1 hour period}}};var receipt = await ecosystemWallet.CreateSessionKey(chainId: 1,signerAddress: await sessionSigner.GetAddress(),durationInSeconds: 3600, // 1 hourgrantFullPermissions: false,callPolicies: callPolicies,transferPolicies: transferPolicies,uid: System.Text.Encoding.UTF8.GetBytes("unique-session-id") // Custom unique identifier);// Create a wildcard session key (works with any address)var wildcardReceipt = await ecosystemWallet.CreateSessionKey(chainId: 1,signerAddress: "0x0000000000000000000000000000000000000000", // Wildcard addressdurationInSeconds: 7200, // 2 hoursgrantFullPermissions: true);
// Allow spending game tokens with daily limitsvar gameTokenPolicy = new List<CallSpec>{new CallSpec{Target = "0xGameTokenContract...",Selector = new byte[] { 0xa9, 0x05, 0x9c, 0xbb }, // transfer(address,uint256)MaxValuePerUse = BigInteger.Parse("1000000000000000000000"), // 1000 tokens per transactionValueLimit = new UsageLimit{LimitType = 2, // Allowance (resets daily)Limit = BigInteger.Parse("10000000000000000000000"), // 10,000 tokens per dayPeriod = 86400 // 1 day}}};
// Allow DEX trades with specific token constraintsvar dexTradingPolicy = new List<CallSpec>{new CallSpec{Target = "0xUniswapV3Router...",Selector = new byte[] { 0x41, 0x4b, 0xf3, 0x89 }, // exactInputSingleMaxValuePerUse = BigInteger.Parse("100000000000000000"), // 0.1 ETH max per tradeValueLimit = new UsageLimit{LimitType = 2, // Daily allowanceLimit = BigInteger.Parse("1000000000000000000"), // 1 ETH per dayPeriod = 86400},Constraints = new List<Constraint>{new Constraint{Condition = 1, // Equal - only allow specific tokenIndex = 0, // First parameter (tokenIn)RefValue = new byte[32], // USDC token address (padded to 32 bytes)Limit = new UsageLimit { LimitType = 0 } // Unlimited usage of this constraint}}}};
// Allow recurring payments to specific servicevar subscriptionPolicy = new List<CallSpec>{new CallSpec{Target = "0xSubscriptionContract...",Selector = new byte[] { 0x12, 0x34, 0x56, 0x78 }, // paySubscription()MaxValuePerUse = BigInteger.Parse("50000000000000000000"), // $50 worth of tokensValueLimit = new UsageLimit{LimitType = 2, // Monthly allowanceLimit = BigInteger.Parse("50000000000000000000"), // $50 per monthPeriod = 2592000 // 30 days},Constraints = new List<Constraint>{new Constraint{Condition = 1, // Equal - only allow payments to specific serviceIndex = 0, // Service ID parameterRefValue = BitConverter.GetBytes(12345).Concat(new byte[28]).ToArray(), // Service ID 12345Limit = new UsageLimit { LimitType = 0 }}}}};
// Allow emergency withdrawals with strict limitsvar emergencyPolicy = new List<TransferSpec>{new TransferSpec{Target = "0x0000000000000000000000000000000000000000", // ETHMaxValuePerUse = BigInteger.Parse("100000000000000000"), // 0.1 ETH per withdrawalValueLimit = new UsageLimit{LimitType = 1, // Lifetime limitLimit = BigInteger.Parse("500000000000000000"), // 0.5 ETH totalPeriod = 0 // Not used for lifetime limits}}};var emergencyReceipt = await ecosystemWallet.CreateSessionKey(chainId: 1,signerAddress: await emergencyWallet.GetAddress(),durationInSeconds: 604800, // 1 weekgrantFullPermissions: false,callPolicies: null,transferPolicies: emergencyPolicy);
BigInteger
: The chain ID for the session key.
string
: The address of the signer for the session key. Use "0x0000000000000000000000000000000000000000"
for wildcard session keys that work with any address.
long
: Duration in seconds for which the session key will be valid.
bool
(optional): Whether to grant full permissions to the session key. When true
, creates a "wildcard" session that ignores call and transfer policies and allows any action. When false
, only the specified call and transfer policies will be applied. Defaults to true
.
Important: When grantFullPermissions
is true
, the callPolicies
and transferPolicies
parameters are ignored.
List<CallSpec>
(optional): List of call policies to apply to the session key. If null
, no call policies will be applied. Only used when grantFullPermissions
is false
.
Target
(string
): The contract address that can be calledSelector
(byte[]
): The function selector (4 bytes) that can be called - use tools like 4byte.directory to find selectorsMaxValuePerUse
(BigInteger
): Maximum ETH value that can be sent per function callValueLimit
(UsageLimit
): Overall ETH spending limits for this call policyConstraints
(List<Constraint>
): Additional parameter constraints for function calls
Selector Examples:
transfer(address,uint256)
:0xa9059cbb
approve(address,uint256)
:0x095ea7b3
swapExactETHForTokens(uint256,address[],address,uint256)
:0x7ff36ab5
List<TransferSpec>
(optional): List of transfer policies to apply to the session key. If null
, no transfer policies will be applied. Only used when grantFullPermissions
is false
.
Target
(string
): The token contract address for transfers- Use
"0x0000000000000000000000000000000000000000"
for native ETH - Use specific token contract addresses for ERC-20 tokens
- Use
MaxValuePerUse
(BigInteger
): Maximum amount that can be transferred per transactionValueLimit
(UsageLimit
): Overall usage limits for transfers of this token
Common Token Examples:
- ETH:
0x0000000000000000000000000000000000000000
- USDC:
0xA0b86a33E6411a3bb4CC4C7b9C5C5C7C7C8C9C0c
(mainnet) - USDT:
0xdAC17F958D2ee523a2206206994597C13D831ec7
(mainnet)
byte[]
(optional): A unique identifier for the session key. If null
, a new GUID will be generated automatically. This UID is used to identify and manage the session key on-chain.
Once a session key is created, you can use these methods to inspect and manage it:
// Check if a signer has full permissions (wildcard access)bool hasFullPermissions = await ecosystemWallet.SignerHasFullPermissions(chainId: 1,signerAddress: await sessionSigner.GetAddress());// Get the call policies for a specific signervar callPolicies = await ecosystemWallet.GetCallPoliciesForSigner(chainId: 1,signerAddress: await sessionSigner.GetAddress());// Get the transfer policies for a specific signervar transferPolicies = await ecosystemWallet.GetTransferPoliciesForSigner(chainId: 1,signerAddress: await sessionSigner.GetAddress());// Get the session expiration timestampvar expirationTimestamp = await ecosystemWallet.GetSessionExpirationForSigner(chainId: 1,signerAddress: await sessionSigner.GetAddress());// Get complete session state including remaining limitsvar sessionState = await ecosystemWallet.GetSessionStateForSigner(chainId: 1,signerAddress: await sessionSigner.GetAddress());// Check remaining limitsforeach (var limit in sessionState.TransferValue){Console.WriteLine($"Transfer limit remaining for {limit.Target}: {limit.Remaining}");}foreach (var limit in sessionState.CallValue){Console.WriteLine($"Call value limit remaining for {limit.Target}.{limit.Selector.ToHex()}: {limit.Remaining}");}
Controls how usage limits are enforced over time:
0
(Unlimited): No limits applied1
(Lifetime): Total limit that never resets2
(Allowance): Limit that resets every period (e.g., daily/hourly spending limits)
Defines how parameter constraints are evaluated:
0
(Unconstrained): No constraint applied1
(Equal): Parameter must equal the reference value2
(Greater): Parameter must be greater than reference value3
(Less): Parameter must be less than reference value4
(GreaterOrEqual): Parameter must be greater than or equal to reference value5
(LessOrEqual): Parameter must be less than or equal to reference value6
(NotEqual): Parameter must not equal the reference value
Defines spending or usage limits over time periods:
public class UsageLimit{public byte LimitType { get; set; } // 0=Unlimited, 1=Lifetime, 2=Allowancepublic BigInteger Limit { get; set; } // The limit amount (ignored if Unlimited)public BigInteger Period { get; set; } // Time period in seconds (only used for Allowance)}
Examples:
- Unlimited:
LimitType = 0
(Limit and Period ignored) - Lifetime limit:
LimitType = 1, Limit = 1000
(max 1000 tokens ever) - Daily allowance:
LimitType = 2, Limit = 100, Period = 86400
(100 tokens per day)
Defines parameter validation and usage limits for function calls:
public class Constraint{public byte Condition { get; set; } // Condition type (0-6, see enum above)public ulong Index { get; set; } // Parameter index to constrain (0-based)public byte[] RefValue { get; set; } // Reference value for comparison (32 bytes)public UsageLimit Limit { get; set; } // Usage limit for this parameter value}
Example Use Cases:
- Limit transfers to specific addresses
- Restrict token amounts in function calls
- Control which contracts can be called
- Set spending limits per recipient
"Execution mode not supported"
- Ensure your EcosystemWallet is created with
ExecutionMode.EIP7702
orExecutionMode.EIP7702Sponsored
"Invalid signer address"
- Verify the signer address is a valid Ethereum address
- Use
"0x0000000000000000000000000000000000000000"
for wildcard sessions
"Duration too short"
- Duration must be greater than 0 seconds
- Consider reasonable session lengths (1 hour to 30 days)
"MaxValueExceeded"
- Transaction value exceeds
MaxValuePerUse
in CallSpec/TransferSpec - Increase the limit or split into smaller transactions
"LifetimeUsageExceeded"
- Total usage has exceeded the lifetime limit
- Create a new session key or increase limits
"AllowanceExceeded"
- Period allowance has been exhausted
- Wait for the next period or create additional session keys
"CallPolicyViolated"
- Attempting to call a contract/function not in the CallSpec list
- Add the required contract and selector to callPolicies
"ConditionFailed"
- Function parameter doesn't meet constraint requirements
- Check parameter values match the expected constraints