Target Base Contract
Overview
TargetBase
is a foundational contract that provides a signature-based authorization system for smart contracts. It enforces strict access controls by combining cryptographic signatures, smart account validation, and replay protection into a single, reusable module.
Application developers can extend TargetBase
to build specialized contracts (e.g., DeFi protocols, marketplaces, or tokenized asset platforms) while inheriting all of its security guarantees.
Core Features
1. Master Key Authorization
A trusted master key signs all authorizations.
The master key can be rotated by the owner or a recovery key for security.
This ensures that only signatures from the current master key are valid.
2. Smart Account Enforcement
Only approved DelegatedAccount implementations can call protected functions.
Enforced using
extcodehash
checks:EOAs are rejected (no direct access).
Contracts with incorrect or empty bytecode are rejected.
Only contracts with the registered
DelegatedAccount
code hash are accepted.
3. Replay Protection
Nonces: Each sender has a sequential nonce. Must match
authData.nonce
.Authorization Hash Tracking: Each authorization (signature + data) is marked as used after execution.
This prevents signature reuse across different calls or chains.
4. Temporal Validation
Authorizations include an expiry timestamp.
Prevents attackers from replaying old signatures long after they were valid.
5. Emergency Recovery
Recovery Key: Dedicated address that can update the master key.
Nonce Reset: Owner can reset user nonces if accounts get stuck.
Authorization Workflow
AuthData
Every protected function must receive an AuthData
struct as its first argument.
It contains:
nonce
→ Sequential replay protection.expiry
→ Timestamp after which the auth is invalid.id
→ Execution hash for the overall operation.executions
→ Array of execution steps for auditability.result
→ ABI-encoded final result or function parameters.sponsorExecutionFee
→ Indicates if fees are sponsored.signature
→ ECDSA signature from the master key.
Authorization Verification (requireAuth)
When a protected function is called:
Implementation Check → Caller must be approved DelegatedAccount.
Nonce Check →
authData.nonce == nonces[msg.sender]
.Expiry Check →
block.timestamp <= authData.expiry
.Hash Generation → Unique hash created from sender, nonce, expiry, result, selector.
Replay Check → Hash must not already exist in
usedAuthorizations
.Signature Check → Recovered signer must match
masterKey
.State Update → Nonce incremented, hash marked used.
Event Emitted →
AuthorizationVerified
.
Extending TargetBase
Developers extend TargetBase
by inheriting it in their own contracts and applying requireAuth
to sensitive functions.
Example: RealEstateInvestment (Without extra parameters)
The RealEstateInvestment
contract extends TargetBase
to implement fractional real estate ownership.
Key extensions:
Inherits both
TargetBase
(for authorization) andERC20
(for fractional tokens).Defines domain-specific structs like
PropertyInfo
,PropertyAnalysisResponse
, andInvestmentRecord
.Implements business logic:
submitPropertyAnalysis
→ Requires a signed analysis result.purchaseTokens
→ Requires signed authorization for each investment.
All core operations use
requireAuth(authData)
to enforce:Signature validation.
DelegatedAccount-only access.
Replay protection.
function submitPropertyAnalysis(AuthData calldata authData)
external
requireAuth(authData)
{
// Decode AI analysis results
PropertyAnalysisResponse memory analysis = abi.decode(authData.result, (PropertyAnalysisResponse));
// Apply domain-specific validation rules
if (analysis.confidence < MIN_CONFIDENCE) revert ConfidenceTooLow();
if (keccak256(bytes(analysis.recommendation)) != keccak256("INVEST")) revert InvalidRecommendation();
// Update property state & emit events
property.totalValue = analysis.propertyValue;
property.isActive = true;
emit PropertyAnalyzed(...);
}
Example 2: TokenSale (With extra parameters)
contract TokenSale {
IERC20 public token;
constructor(address _token) {
token = IERC20(_token);
}
function purchaseTokens(
AuthData calldata authData, // comes from krnl "authData_result"
uint256 amount // comes from krnl "parameters"
) external {
// ✅ 1. Verify the AuthData
require(verifyAuthData(authData), "Invalid AuthData");
// ✅ 2. Process token purchase
require(amount > 0, "Zero amount");
require(token.balanceOf(address(this)) >= amount, "Insufficient liquidity");
token.transfer(msg.sender, amount);
}
}
From the DSL we wrote earlier in 2. Target Contract Details this is how the structure will look like with the extra parameter:
"function": "purchaseTokens((uint256,uint256,bytes32,(bytes32,bytes,bytes)[],bytes,bool,bytes),uint256)",
"authData_result": "${construct-authdata-evm.result}",
"parameters": [
{
"name": "amount",
"type": "uint256",
"value": "1000000000000000000"
}
]
authData_result
→ fills the first argument (AuthData calldata authData
)parameters
→ supplies extra arguments (uint256 amount
)
Benefits of Inheriting TargetBase
Security out of the box: No need to reimplement replay protection or signature verification.
Standardized authorization: Uniform way to authorize actions across contracts.
Extensible: Each new contract only needs to define its domain-specific logic.
Composable: Multiple
TargetBase
-derived contracts can interoperate securely.
Best Practices
AuthData as the first parameter
All functions requiring authorization must have
AuthData calldata authData
first.Ensures deterministic ABI encoding.
Validate extra parameters
Never trust DSL inputs blindly.
Use
require
or custom errors for range, zero addresses, or business logic constraints.Example:
require(amount > 0, "Amount must be positive"); require(recipient != address(0), "Invalid recipient");
Use events for auditability
Emit events for:
Authorization verified
Master key update
Property or token transactions
Enables off-chain monitoring & workflow debugging.
Fail fast and explicitly
Custom errors instead of generic
require
messages save gas and improve readability.
Last updated