Complete API reference for the mpc-wallet Python package.
pip install mpc-wallet
# or
poetry add mpc-wallet
# or
uv add mpc-walletfrom mpc_wallet import MpcAgentWallet, WalletConfig, PolicyConfig, PartyRole, ChainType
wallet = MpcAgentWallet(WalletConfig(
role=PartyRole.AGENT,
policy=PolicyConfig().with_daily_limit(ChainType.EVM, int(10e18)),
))Main class for managing MPC-secured wallets.
def __init__(self, config: WalletConfig | None = None) -> NoneCreate a new MPC wallet instance.
wallet = MpcAgentWallet(WalletConfig(
role=PartyRole.AGENT,
policy=PolicyConfig(),
))| Parameter | Type | Description |
|---|---|---|
config.role |
PartyRole |
Party role (AGENT, USER, RECOVERY) |
config.policy |
PolicyConfig |
Policy configuration |
config.key_share |
KeyShare |
Existing key share to load |
Create a wallet from an existing key share.
wallet = MpcAgentWallet.from_share(key_share, policy=PolicyConfig())Create a key generation session.
session = wallet.create_keygen_session(KeygenConfig(
role=PartyRole.AGENT,
session_id=str(uuid.uuid4()),
threshold=2,
parties=3,
))Set the key share after key generation.
Get the current key share.
Check if a key share is loaded.
Property to get the party role.
Get the wallet's Ethereum address.
address = wallet.get_address()
# '0x742d35Cc6634C0532925a3b844Bc9e7595f...'Get the wallet's compressed public key.
Get address for a specific chain type.
eth_address = wallet.get_chain_address(ChainType.EVM)
sol_address = wallet.get_chain_address(ChainType.SOLANA)Set the policy configuration.
Get the current policy configuration.
Evaluate a transaction against the policy.
decision = wallet.evaluate_policy(TransactionRequest(
request_id="tx-1",
chain=ChainType.EVM,
to="0x...",
value="1000000000000000000",
chain_id=1,
))
if not decision.approved:
print(f"Rejected: {decision.reason}")Create a signing session.
message_hash = wallet.hash_transaction(tx)
session = wallet.create_signing_session(
SigningConfig(
session_id=str(uuid.uuid4()),
parties=[PartyRole.AGENT, PartyRole.USER],
threshold=2,
),
message_hash
)Hash a message using Keccak256.
Hash a message with Ethereum prefix.
Create a transaction hash for signing.
Export wallet state (without secrets) for debugging.
Get wallet info summary.
Manages the distributed key generation (DKG) protocol.
session = KeygenSession(KeygenConfig(
role=PartyRole.AGENT,
session_id="session-123",
threshold=2,
parties=3,
))Generate round 1 (commitment) message.
Process round 1 messages from other parties.
Generate round 2 (key share) message.
Process round 2 messages from other parties.
Generate round 3 (verification) message.
Finalize key generation and return the key share.
Property to get current session state.
Manages the distributed signature generation (DSG) protocol.
session = SigningSession(
SigningConfig(
session_id="session-456",
parties=[PartyRole.AGENT, PartyRole.USER],
threshold=2,
),
key_share,
message_hash
)Generate round 1 message.
Process round 1 messages from other signing parties.
Generate round 2 message.
Finalize signing and return the signature.
Configuration for the policy engine.
policy = PolicyConfig()with_spending_limits(chain: ChainType, per_tx: int = 0, daily: int = 0, weekly: int = 0) -> PolicyConfig
Add spending limits for a chain.
policy.with_spending_limits(
ChainType.EVM,
per_tx=int(1e18), # 1 ETH
daily=int(10e18), # 10 ETH
weekly=int(50e18), # 50 ETH
)Add address whitelist.
policy.with_whitelist([
"0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
])Add address blacklist.
with_time_bounds(start_hour: int, end_hour: int, allowed_days: list[int] | None = None, timezone: str = "UTC") -> PolicyConfig
Add time restrictions.
policy.with_time_bounds(
start_hour=9,
end_hour=17,
allowed_days=[0, 1, 2, 3, 4], # Monday-Friday
timezone="America/New_York",
)with_contract_restrictions(allowed_contracts: list[str] | None = None, blocked_selectors: list[str] | None = None) -> PolicyConfig
Add contract interaction restrictions.
policy.with_contract_restrictions(
allowed_contracts=["0x..."],
blocked_selectors=["0xa9059cbb"], # Block raw ERC20 transfers
)Require recovery guardian approval for transactions above threshold.
Evaluates transactions against configured policies.
engine = PolicyEngine(policy_config)Evaluate a transaction against all policies.
decision = engine.evaluate(tx)
# PolicyDecision(approved=True)
# or
# PolicyDecision(approved=False, reason="Daily spending limit exceeded")Property to get the current policy configuration.
Get current spending statistics.
@dataclass
class WalletConfig:
role: PartyRole = PartyRole.AGENT
policy: PolicyConfig | None = None
key_share: KeyShare | None = None@dataclass
class KeygenConfig:
role: PartyRole
session_id: str
threshold: int = 2
parties: int = 3@dataclass
class SigningConfig:
session_id: str
parties: list[PartyRole]
threshold: int = 2@dataclass
class TransactionRequest:
request_id: str
chain: ChainType
to: str
value: str
data: str | None = None
gas_limit: int | None = None
chain_id: int | None = None
timestamp: int | None = None
metadata: dict[str, Any] | None = None@dataclass
class KeyShare:
party_id: int
role: PartyRole
public_key: str # Compressed public key (hex)
eth_address: str # Derived Ethereum address
secret_share: str # Encrypted secret share (base64)
verification_key: str
threshold: int
parties: int@dataclass
class Signature:
r: str # Hex string with 0x prefix
s: str # Hex string with 0x prefix
recovery_id: int # 0 or 1@dataclass
class PolicyDecision:
approved: bool
reason: str | None = None
requires_additional_approval: bool = False@dataclass
class ProtocolMessage:
type: MessageType # "broadcast" or "direct"
from_party: int
to_party: int | None = None
round: int
data: str # base64 encodedclass PartyRole(Enum):
AGENT = 0
USER = 1
RECOVERY = 2class ChainType(Enum):
EVM = 0
SOLANA = 1
BITCOIN = 2class SessionState(Enum):
INITIALIZED = "initialized"
ROUND1 = "round1"
ROUND2 = "round2"
ROUND3 = "round3"
COMPLETE = "complete"
FAILED = "failed"class ErrorCode(Enum):
INVALID_CONFIG = "INVALID_CONFIG"
INVALID_PARTY_ID = "INVALID_PARTY_ID"
THRESHOLD_NOT_MET = "THRESHOLD_NOT_MET"
POLICY_VIOLATION = "POLICY_VIOLATION"
SIGNING_FAILED = "SIGNING_FAILED"
KEYGEN_FAILED = "KEYGEN_FAILED"
STORAGE_ERROR = "STORAGE_ERROR"
NETWORK_ERROR = "NETWORK_ERROR"
TIMEOUT = "TIMEOUT"
UNKNOWN = "UNKNOWN"class MpcWalletError(Exception):
def __init__(self, code: ErrorCode, message: str, cause: Exception | None = None):
self.code = code
self.message = message
self.cause = causefrom mpc_wallet import MpcWalletError, ErrorCode
try:
await wallet.sign_transaction(tx)
except MpcWalletError as e:
if e.code == ErrorCode.POLICY_VIOLATION:
print(f"Policy rejected transaction: {e.message}")
elif e.code == ErrorCode.THRESHOLD_NOT_MET:
print("Not enough parties for signing")
elif e.code == ErrorCode.TIMEOUT:
print("Operation timed out")
else:
print(f"Wallet error: {e}")Ethereum/EVM chain adapter.
from mpc_wallet.chains import EvmAdapter
adapter = EvmAdapter(
rpc_urls=["https://eth.llamarpc.com", "https://rpc.ankr.com/eth"],
chain_id=1,
)
balance = await adapter.get_balance("0x...")
tx = await adapter.build_transaction(
to="0x...",
value="1000000000000000000",
)Get native token balance.
Build an unsigned transaction.
Broadcast a signed transaction.
Derive Ethereum address from public key.
Solana chain adapter.
from mpc_wallet.chains import SolanaAdapter
adapter = SolanaAdapter(
rpc_url="https://api.mainnet-beta.solana.com",
commitment="confirmed",
)Get SOL balance.
Build an unsigned transaction.
Broadcast a signed transaction.
from mpc_wallet.utils import format_ether, parse_ether, format_gwei
format_ether(10**18) # "1.0"
parse_ether("1.5") # 1500000000000000000
format_gwei(10**9) # "1.0"from mpc_wallet.utils import is_valid_address, is_valid_hex
is_valid_address("0x742d35Cc6634C0532925a3b844Bc9e7595f12345") # True
is_valid_hex("0x1234abcd") # TrueAll I/O operations support asyncio:
import asyncio
from mpc_wallet import MpcAgentWallet
async def main():
wallet = MpcAgentWallet()
# Async key share loading
await wallet.load_key_share("my-wallet", "password")
# Async transaction signing
signature = await wallet.sign_transaction(tx)
asyncio.run(main())The package includes full type hints and supports mypy/pyright:
from mpc_wallet import MpcAgentWallet, TransactionRequest, PolicyDecision
def process_transaction(wallet: MpcAgentWallet, tx: TransactionRequest) -> PolicyDecision:
return wallet.evaluate_policy(tx)from langchain.tools import BaseTool
from mpc_wallet import MpcAgentWallet, TransactionRequest, ChainType
class WalletSendTool(BaseTool):
name = "wallet_send"
description = "Send cryptocurrency from the MPC wallet"
def __init__(self, wallet: MpcAgentWallet):
super().__init__()
self.wallet = wallet
def _run(self, to: str, value: str) -> str:
tx = TransactionRequest(
request_id=str(uuid.uuid4()),
chain=ChainType.EVM,
to=to,
value=str(int(float(value) * 10**18)),
chain_id=1,
)
decision = self.wallet.evaluate_policy(tx)
if not decision.approved:
return f"Rejected: {decision.reason}"
return f"Transaction pending approval: {tx.request_id}"from fastapi import FastAPI, HTTPException
from mpc_wallet import MpcAgentWallet, TransactionRequest
app = FastAPI()
wallet = MpcAgentWallet()
@app.post("/transactions")
async def create_transaction(tx: TransactionRequest):
decision = wallet.evaluate_policy(tx)
if not decision.approved:
raise HTTPException(status_code=403, detail=decision.reason)
# Create approval request...
return {"status": "pending_approval", "request_id": tx.request_id}See the examples directory for complete working examples: