Smart Wallets

By @friedgerarrow-up-right

Contract Summary

There's many different implementations of a smart contract wallet available for developers to build with depending on their user's needs. The specific implementation showcased here is the Smart Wallet with Rules contract, which is a sophisticated wallet abstraction that enables programmable spending rules and multi-admin governance. Built by @friedgerarrow-up-right, this contract demonstrates advanced patterns for creating customizable wallet logic with security levels, activity monitoring, and extension capabilities.

Key Features:

  • Rule-Based Access Control - Configurable security levels (no rules, standard rules, emergency rules) that govern STX transfers and extension calls

  • Multi-Admin Support - Multiple principals can be designated as admins with the ability to manage other admins and security settings

  • Activity Monitoring - Tracks last transaction time to detect wallet inactivity (10 weeks on mainnet, 1 second on testnet)

  • Extension System - Modular architecture allowing custom extension contracts to add new functionality

  • Token Support - Built-in support for SIP-010 fungible tokens and SIP-009 NFT transfers

What Developers Can Learn:

  • How to implement customizable access control with rule-set traits

  • Multi-admin patterns with self-protection (admins cannot disable themselves)

  • Activity tracking using block timestamps for inactivity detection

  • Extension pattern for modular smart contract functionality

  • Dynamic trait selection based on security levels



Function-by-Function Breakdown

STX Transfer Functions

stx-transfer (amount uint) (recipient principal) (memo (optional (buff 34)))

Transfers STX from the smart wallet to a recipient, first checking with the current rule-set if the transfer is allowed. Updates the last transaction time for activity tracking and uses as-contract to transfer from the wallet's balance.

Extension System Functions

extension-call (extension <extension-trait>) (payload (buff 2048))

Calls an external extension contract with arbitrary payload data, after checking with the current rule-set if the extension call is allowed. Enables modular functionality to be added to the wallet.

SIP-010 Token Functions

sip010-transfer (amount uint) (recipient principal) (memo (optional (buff 34))) (sip010 <sip-010-trait>)

Transfers SIP-010 fungible tokens from the smart wallet to a recipient. Currently has placeholder validation logic that always allows transfers.

SIP-009 NFT Functions

sip009-transfer (nft-id uint) (recipient principal) (sip009 <sip-009-trait>)

Transfers SIP-009 NFTs from the smart wallet to a recipient. Currently has placeholder validation logic that always allows transfers.

Admin Management Functions

enable-admin (admin principal) (enabled bool)

Adds or removes admin privileges for a principal. Only callable by existing admins, and includes self-protection to prevent admins from disabling themselves.

set-security-level (new-level uint)

Changes the wallet's security level (0 = no rules, 1 = standard rules, 2+ = emergency rules). Only callable by admins, this determines which rule-set governs wallet operations.

Rule Validation Functions (Private)

is-allowed-stx (rules <rule-set-trait>) (amount uint) (recipient principal) (memo (optional (buff 34)))

Private function that delegates STX transfer validation to the current rule-set contract.

is-allowed-extension (rules <rule-set-trait>) (extension <extension-trait>) (payload (buff 2048))

Private function that delegates extension call validation to the current rule-set contract.

is-allowed-sip010 (sip010 <sip-010-trait>) (amount uint) (recipient principal) (memo (optional (buff 34)))

Private function for SIP-010 transfer validation. Currently always returns true.

is-allowed-sip009 (sip009 <sip-009-trait>) (amount uint) (recipient principal)

Private function for SIP-009 transfer validation. Currently always returns true.

Access Control & Utility Functions

is-admin-calling

Read-only function that verifies if the contract caller is an authorized admin. Returns an error if not authorized.

current-rules

Read-only function that returns the appropriate rule-set trait based on the current security level (0 = no-rules, 1 = standard-rules, 2+ = emergency-rules).

to-trait (trait <rule-set-trait>)

Helper function that converts a rule-set contract to a trait for use in validation functions.

Activity Tracking Functions

get-time

Read-only function that retrieves the timestamp of the previous Stacks block.

is-inactive

Read-only function that checks if the wallet has been inactive for longer than the activity period (10 weeks on mainnet, 1 second on testnet).

Traits Used

extension-trait

Custom trait that defines the interface for wallet extension contracts that can add modular functionality.

rule-set-trait

Custom trait that defines the interface for rule-set contracts that govern wallet operations.

sip-010-trait

Standard SIP-010 fungible token trait for token transfers.

sip-009-trait

Standard SIP-009 NFT trait for NFT transfers.


Key Concepts

Programmable Security Levels

The wallet implements a three-tier security system through the security-level variable. Level 0 applies no restrictions, level 1 uses standard rules, and level 2+ activates emergency rules. This allows the wallet to dynamically adjust security posture based on threat conditions.

Rule-Set Trait Pattern

The contract uses a trait-based architecture for validation logic, allowing different rule contracts to be swapped based on security level. The current-rules function dynamically selects which rule-set to use, enabling flexible and upgradeable access control without modifying the core wallet contract.

Multi-Admin Governance

The contract supports multiple administrators through a admins map. The enable-admin function includes a self-protection mechanism ((asserts! (not (is-eq admin contract-caller)) err-forbidden)) preventing admins from accidentally or maliciously removing their own access.

Activity-Based Inactivity Detection

The contract tracks the timestamp of the last transaction in last-tx-time and compares it against an activity period (10 weeks on mainnet). The is-inactive function can be used by external contracts (like the inactive-observer admin) to detect dormant wallets and potentially trigger recovery mechanisms.

Extension Modularity

The extension system allows new functionality to be added without modifying the core wallet. Extensions receive a 2048-byte payload and can execute arbitrary logic while being subject to rule-set validation. This enables features like scheduled payments, multi-sig requirements, or DeFi integrations.

Last updated

Was this helpful?