Usage
What You're Building
Think of TargetBase as your smart contract's security bouncer. It's a battle-tested foundation that gives you signature-based authorization, smart account enforcement, and all the protection you need for EIP-7702 delegated accounts—without having to reinvent the wheel.
This guide walks you through extending TargetBase to build your own secure contracts. We'll use the RealEstateInvestment contract as our real-world example because, well, nothing teaches better than actual code.
What TargetBase Does For You
Here's what you get out of the box:
Signature-based authorization – Only calls signed by your master key get through
Smart account validation – Enforces EIP-7702 compliance (no random EOAs sneaking in)
Replay attack protection – Nonces and hash tracking ensure each authorization works exactly once
Time-bound authorizations – Set expiry timestamps so old signatures can't haunt you
Emergency recovery – Because sometimes you need a backup plan
Multi-source execution chains – Perfect for when you need to aggregate data from multiple sources
Think of it as a security framework that handles all the hard parts so you can focus on your business logic.
The Core Building Blocks
AuthData
Every protected function needs one of these. It's like a VIP pass that proves the caller has permission:
The Authorization Players
Master Key – The VIP who signs everything. This is your authorization authority.
Recovery Key – Your emergency contact. Can rotate the master key if things go wrong.
Owner – The admin. Controls contract settings and upgrades.
DelegatedAccount – The only type of account allowed to call your protected functions (EIP-7702 smart accounts only)
How to Extend TargetBase (The Three-Step Implementation)
Step 1: Set Up Your Contract
Start by inheriting from TargetBase. You can mix in other contracts too—we're using ERC20 in our real estate example:
Step 2: Define Your Data Structures
Before you do anything else, define the structs that will carry your data which is basically the result your are expected from the KRNL node as a part of the workflow execution. These are what you'll encode/decode in authData.result:
Important: The fields in your struct should be alphabetically ordered when you're working with external data sources. This ensures consistent encoding/decoding across different systems.
Step 2: Protect Your Functions
Now when you integrate KRNL to your smart contract, you use requireAuth(authData) modifier to do the basic validation check like your nonce, expiry, etc and make AuthData your first parameter:
Step 3: Decode Your Data (When You Need It)
If you're working with multi-source execution chains or need to extract data from the authorization:
Real-World Example: Tokenizing Real Estate
Let's look at how the RealEstateInvestment contract does it. This contract lets people buy fractional ownership of properties using USDC. It needs TargetBase because property analysis data comes from multiple sources (Zillow, Census data, AI analysis) and needs to be verified before allowing investments.
What's happening here?
The constructor handles both TargetBase and ERC20 initialization
submitPropertyAnalysisdecodes complex multi-source data and validates itpurchaseTokenscombines authorization with business parametersEvents include
authData.nonceandauthData.idfor complete traceability
Things to Avoid
When Setting Up Your Constructor
No zero addresses – TargetBase will reject them. Every address parameter matters.
DelegatedAccount must be real – It needs to be an actual deployed contract with code. No empty addresses or EOAs.
Order matters – Pass the four TargetBase parameters first, in order:
_authKey, _recoveryKey, _owner, _delegatedAccountImpl
When Writing Protected Functions
AuthData always comes first – It's not just convention, it's how the pattern works.
function myFunc(AuthData calldata authData, ...)Use the modifier – Don't forget
requireAuth(authData). That's where all the magic happens.Include context in events – Always emit
authData.nonceandauthData.idin your events. Future you will thank present you when debugging!
The Security Guarantees
Here's what TargetBase enforces automatically:
EIP-7702 only – No EOAs allowed. Only properly delegated smart accounts get through.
Sequential nonces – Can't skip ahead or go backward. If Alice is on nonce 5, her next call must use nonce 5, then 6, then 7...
Expiry matters – That timestamp isn't just for show. Expired = rejected.
One-time use – Each authorization is like a ticket. Once it's used, it's burned. No replays, no exceptions.
Best Practices
Emit meaningful events
Include authData.nonce and authData.id in every event. Six months from now when you're debugging a production issue, you'll want that audit trail. Trust me.
Validate everything Just because data made it through authorization doesn't mean it's correct. Always validate decoded results before using them. Check ranges, verify checksums, enforce business rules.
Use custom errors
TargetBase uses them for a reason—they're gas-efficient and more descriptive. revert InsufficientFunds() beats require(balance > 0, "Insufficient funds") every time.
Protect against reentrancy
TargetBase includes nonReentrant protection. Use it on any function that changes state or moves value around.
Keep view functions simple
Don't use requireAuth on view or pure functions. They don't change state, so they don't need authorization. Save the gas.
Use Ownable for admin stuff
TargetBase inherits from Ownable, so you get onlyOwner for free. Use it for administrative functions that shouldn't go through the auth flow.
Three Common Patterns You Can Use
Pattern 1: Simple Authorization (Just Verify, No Data)
Pattern 2: Multi-Source Data Pipeline
Pattern 3: Authorization + Business Parameters
When to use each:
Pattern 1: Permission changes, state toggles, simple actions
Pattern 2: External data validation, multi-API aggregation, complex analysis
Pattern 3: Most common! Authorized actions with user-provided parameters
Last updated

