From fe960f46a2e315dee65ca75d7c621c024a9ca4ea Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:14:55 +0000 Subject: [PATCH 1/2] docs: add Account Keychain examples for Python and Go SDKs Mirror the cast keychain documentation for Python (AccountKeychain class) and Go (keychain package) with examples for authorize, revoke, spending limits, call scopes, signing, and querying. Co-Authored-By: grandizzy <38490174+grandizzy@users.noreply.github.com> Amp-Thread-ID: https://ampcode.com/threads/T-019d9747-8dba-7467-82a2-9cb7b1286188 --- src/pages/sdk/go/index.mdx | 123 +++++++++++++++++++++++++++++ src/pages/sdk/python/index.mdx | 136 +++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) diff --git a/src/pages/sdk/go/index.mdx b/src/pages/sdk/go/index.mdx index c98fdf77..85446629 100644 --- a/src/pages/sdk/go/index.mdx +++ b/src/pages/sdk/go/index.mdx @@ -285,6 +285,128 @@ for _, resp := range responses { } ``` +## Account Keychain + +The `keychain` package provides typed helpers for Tempo's [Account Keychain precompile](/protocol/transactions/AccountKeychain), enabling access key management and signing directly from Go. + +:::info +Account Keychain operations only work on Tempo networks. +::: + +```go [keychain_manage.go] +package main + +import ( + "context" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/tempoxyz/tempo-go/pkg/client" + "github.com/tempoxyz/tempo-go/pkg/keychain" + "github.com/tempoxyz/tempo-go/pkg/signer" + "github.com/tempoxyz/tempo-go/pkg/transaction" +) + +func main() { + c := client.New("https://rpc.tempo.xyz") + s, _ := signer.NewSigner("0xYOUR_PRIVATE_KEY") + + ctx := context.Background() + nonce, _ := c.GetTransactionCount(ctx, s.Address().Hex()) + + accessKeyAddr := common.HexToAddress("") + + // Authorize a new access key (secp256k1, no expiry): + restrictions := keychain.NewKeyRestrictions(0) + call, _ := keychain.AuthorizeKey(accessKeyAddr, keychain.SignatureTypeSecp256k1, restrictions) + + tx := transaction.NewBuilder(big.NewInt(4217)). + SetNonce(nonce). + SetGas(200000). + SetMaxFeePerGas(big.NewInt(20000000000)). + SetMaxPriorityFeePerGas(big.NewInt(1000000000)). + AddCall(call.To, big.NewInt(0), call.Data). + Build() + + // Authorize with a spending limit: + token := common.HexToAddress("") + restrictions = keychain.NewKeyRestrictions(0). + WithLimits([]keychain.TokenLimit{{Token: token, Amount: big.NewInt(1_000_000)}}) + call, _ = keychain.AuthorizeKey(accessKeyAddr, keychain.SignatureTypeSecp256k1, restrictions) + + // Authorize with call scopes (restrict to specific contracts/functions): + scope := keychain.NewCallScopeBuilder(token). + Transfer(nil). + Approve(nil). + Build() + restrictions = keychain.NewKeyRestrictions(0). + WithAllowedCalls([]keychain.CallScope{scope}) + call, _ = keychain.AuthorizeKey(accessKeyAddr, keychain.SignatureTypeSecp256k1, restrictions) + + // Full example: 24h expiry + spending limit + call scope: + expiry := uint64(time.Now().Add(24 * time.Hour).Unix()) + restrictions = keychain.NewKeyRestrictions(expiry). + WithLimits([]keychain.TokenLimit{{Token: token, Amount: big.NewInt(1_000_000)}}). + WithAllowedCalls([]keychain.CallScope{ + keychain.NewCallScopeBuilder(token).Transfer(nil).Build(), + }) + call, _ = keychain.AuthorizeKey(accessKeyAddr, keychain.SignatureTypeSecp256k1, restrictions) + + // Revoke an access key (permanent, cannot be re-authorized): + call, _ = keychain.RevokeKey(accessKeyAddr) + + // Update spending limit for a key-token pair: + call, _ = keychain.UpdateSpendingLimit(accessKeyAddr, token, big.NewInt(2_000_000)) + + // Replace all call scopes for a key: + call, _ = keychain.SetAllowedCalls(accessKeyAddr, []keychain.CallScope{ + keychain.NewCallScopeBuilder(token).Transfer(nil).Build(), + }) + + // Remove a target contract from allowed call list: + call, _ = keychain.RemoveAllowedCalls(accessKeyAddr, token) + + _ = ctx + _ = tx + _ = call +} +``` + +### Signing with an Access Key + +Use `keychain.SignWithAccessKey` to sign a transaction as an access key holder: + +```go [access_key_sign.go] +accessKeySigner, _ := signer.NewSigner("") +rootAccount := common.HexToAddress("") + +tx := transaction.NewBuilder(big.NewInt(4217)). + SetNonce(nonce). + SetGas(100000). + SetMaxFeePerGas(big.NewInt(20000000000)). + SetMaxPriorityFeePerGas(big.NewInt(1000000000)). + AddCall(recipient, big.NewInt(0), data). + Build() + +keychain.SignWithAccessKey(tx, accessKeySigner, rootAccount) // [!code hl] +serialized, _ := transaction.Serialize(tx, nil) +hash, _ := c.SendRawTransaction(ctx, serialized) +``` + +### Query Remaining Spending Limit + +```go [query_limit.go] +calldata := keychain.EncodeGetRemainingLimitCalldata( + common.HexToAddress(""), + common.HexToAddress(""), + common.HexToAddress(""), +) +result, _ := c.Call(ctx, keychain.GetKeychainAddress().Hex(), calldata) +remaining := keychain.ParseRemainingLimitResult(result) +fmt.Printf("Remaining: %s\n", remaining.String()) +``` + ## Packages | Package | Description | @@ -292,6 +414,7 @@ for _, resp := range responses { | `transaction` | TempoTransaction encoding, signing, and validation | | `client` | RPC client for interacting with Tempo nodes | | `signer` | Key management and signature generation | +| `keychain` | Account Keychain precompile: access key management and signing | ## Next Steps diff --git a/src/pages/sdk/python/index.mdx b/src/pages/sdk/python/index.mdx index 67a359f2..7e6f08c4 100644 --- a/src/pages/sdk/python/index.mdx +++ b/src/pages/sdk/python/index.mdx @@ -214,6 +214,142 @@ tx = TempoTransaction.create( ) ``` +## Account Keychain + +The `AccountKeychain` class provides typed helpers for Tempo's [Account Keychain precompile](/protocol/transactions/AccountKeychain), enabling access key management directly from Python. + +:::info +Account Keychain operations only work on Tempo networks. +::: + +```python [keychain.py] +from pytempo import ( + TempoTransaction, Call, + KeyRestrictions, SignatureType, TokenLimit, CallScope, +) +from pytempo.contracts import AccountKeychain, ALPHA_USD +from web3 import Web3 + +w3 = Web3(Web3.HTTPProvider("https://rpc.tempo.xyz")) + +# Authorize a new access key (secp256k1, no expiry): +call = AccountKeychain.authorize_key( + key_id="", + signature_type=SignatureType.SECP256K1, + restrictions=KeyRestrictions(expiry=0), +) +tx = TempoTransaction.create( + chain_id=w3.eth.chain_id, + gas_limit=200_000, + max_fee_per_gas=w3.eth.gas_price * 2, + max_priority_fee_per_gas=w3.eth.gas_price, + nonce=w3.eth.get_transaction_count(account.address), + calls=(call,), +) + +# Authorize with a spending limit: +call = AccountKeychain.authorize_key( + key_id="", + signature_type=SignatureType.SECP256K1, + restrictions=KeyRestrictions( + expiry=0, + limits=[TokenLimit(token=ALPHA_USD, limit=1_000_000)], + ), +) + +# Authorize with call scopes (restrict to specific contracts/functions): +call = AccountKeychain.authorize_key( + key_id="", + signature_type=SignatureType.SECP256K1, + restrictions=KeyRestrictions( + expiry=0, + allowed_calls=[ + CallScope.transfer(target=ALPHA_USD), + CallScope.approve(target=ALPHA_USD), + ], + ), +) + +# Full example: 24h expiry + spending limit + call scope: +import time +expiry = int(time.time()) + 86400 +call = AccountKeychain.authorize_key( + key_id="", + signature_type=SignatureType.SECP256K1, + restrictions=KeyRestrictions( + expiry=expiry, + limits=[TokenLimit(token=ALPHA_USD, limit=1_000_000)], + allowed_calls=[CallScope.transfer(target=ALPHA_USD)], + ), +) + +# Revoke an access key (permanent, cannot be re-authorized): +call = AccountKeychain.revoke_key(key_id="") + +# Update spending limit for a key-token pair: +call = AccountKeychain.update_spending_limit( + key_id="", + token=str(ALPHA_USD), + new_limit=2_000_000, +) + +# Replace all call scopes for a key: +call = AccountKeychain.set_allowed_calls( + key_id="", + scopes=[ + CallScope.transfer(target=ALPHA_USD), + CallScope.unrestricted(target=""), + ], +) + +# Remove a target contract from allowed call list: +call = AccountKeychain.remove_allowed_calls( + key_id="", + target="", +) + +# Query key info (read-only): +key_info = AccountKeychain.get_key( + w3, + account_address="", + key_id="", +) +print(key_info) +# {'signature_type': 0, 'key_id': '0x...', 'expiry': 1893456000, ...} + +# Query remaining spending limit: +remaining = AccountKeychain.get_remaining_limit( + w3, + account_address="", + key_id="", + token_address=str(ALPHA_USD), +) +print(f"Remaining: {remaining}") +``` + +### Signing with an Access Key + +Use `sign_access_key` to sign a transaction as an access key holder: + +```python [access_key_sign.py] +from pytempo import TempoTransaction, Call + +tx = TempoTransaction.create( + chain_id=w3.eth.chain_id, + gas_limit=100_000, + max_fee_per_gas=w3.eth.gas_price * 2, + max_priority_fee_per_gas=w3.eth.gas_price, + nonce=w3.eth.get_transaction_count(root_account_address), + calls=(Call.create(to=""),), +) + +signed_tx = tx.sign_access_key( # [!code hl] + access_key_private_key="", # [!code hl] + root_account="", # [!code hl] +) # [!code hl] +tx_hash = w3.eth.send_raw_transaction(signed_tx.encode()) +``` + ## Next Steps After setting up the Python SDK, you can: From 6844bf73ae814f356347417c30ea41d0eed8ea2c Mon Sep 17 00:00:00 2001 From: Jennifer <5339211+jenpaff@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:09:04 +0100 Subject: [PATCH 2/2] fix: update info boxes to mention T3 requirement for enhanced access key features Amp-Thread-ID: https://ampcode.com/threads/T-019d9c20-7684-713e-ab50-afbb08c9d533 Co-authored-by: Amp --- src/pages/sdk/go/index.mdx | 2 +- src/pages/sdk/python/index.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/sdk/go/index.mdx b/src/pages/sdk/go/index.mdx index 85446629..0d64006a 100644 --- a/src/pages/sdk/go/index.mdx +++ b/src/pages/sdk/go/index.mdx @@ -290,7 +290,7 @@ for _, resp := range responses { The `keychain` package provides typed helpers for Tempo's [Account Keychain precompile](/protocol/transactions/AccountKeychain), enabling access key management and signing directly from Go. :::info -Account Keychain operations only work on Tempo networks. +Enhanced access key features — periodic spending limits and call scoping — require the [T3 network upgrade](/protocol/upgrades/t3). ::: ```go [keychain_manage.go] diff --git a/src/pages/sdk/python/index.mdx b/src/pages/sdk/python/index.mdx index 7e6f08c4..e961883c 100644 --- a/src/pages/sdk/python/index.mdx +++ b/src/pages/sdk/python/index.mdx @@ -219,7 +219,7 @@ tx = TempoTransaction.create( The `AccountKeychain` class provides typed helpers for Tempo's [Account Keychain precompile](/protocol/transactions/AccountKeychain), enabling access key management directly from Python. :::info -Account Keychain operations only work on Tempo networks. +Enhanced access key features — periodic spending limits and call scoping — require the [T3 network upgrade](/protocol/upgrades/t3). ::: ```python [keychain.py]