In Part 1, you learned how to schedule future smart contract calls using Hedera’s Schedule Service. Now, let’s build something more sophisticated: a capacity-aware DeFi rebalancer that automatically adjusts its scheduling strategy based on network conditions. What makes this advanced? Most blockchain automation requires off-chain infrastructure to periodically check and execute operations. Even with Hedera’s Schedule Service, naively scheduling all operations at fixed intervals can create network congestion when many contracts compete for the same execution window. This tutorial demonstrates how to build intelligent on-chain automation that:Documentation Index
Fetch the complete documentation index at: https://hedera-0c6e0218-feat-hip-1313-high-volume-entity-creation.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
- Queries network capacity before scheduling operations
- Uses exponential backoff with jitter to find optimal execution times
- Self-sustains by automatically rescheduling after each execution
- Gracefully handles network congestion and capacity constraints
- Supports multiple scheduling methods (
scheduleCallandscheduleCallWithPayer) - Demonstrates one-shot immediate execution using
executeCallOnPayerSignature
You can take a look at the complete code in the
tutorial-hss-rebalancer-capacity-aware
repository.
What You’ll Build
ARebalancerCapacityAware contract that:
- Starts a rebalancing loop with configurable intervals
- Checks network capacity using
hasScheduleCapacity()before scheduling - Applies intelligent retry logic with exponential backoff and randomized jitter
- Supports two scheduling methods:
scheduleCallandscheduleCallWithPayer - Executes rebalances automatically via scheduled transactions
- Reschedules itself after each execution, creating a self-sustaining loop
- Demonstrates one-shot execution using
executeCallOnPayerSignature - Can be stopped by canceling pending scheduled transactions
- DeFi vault rebalancing
- Periodic token distributions
- Automated treasury management
- Time-based protocol operations
Prerequisites
- Completion of Part 1: Schedule Smart Contract Calls
- ECDSA account from the Hedera Portal
- Understanding of DeFi rebalancing concepts
Table of Contents
- Setup Project
- Step 1: Understanding the Architecture
- Step 2: Create the Rebalancer Contract
- Step 3: Deploy the Contract
- Step 4: Configure the Contract
- Step 5: Start Rebalancing
- Step 6: Monitor Rebalancing Operations
- Step 7: Stop Rebalancing
- Step 8: One-Shot Immediate Execution (Optional)
- Step 9: Run Tests (Optional)
- Conclusion
- Additional Resources
Setup Project
If you completed Part 1, you can use the same project. Otherwise, set up a new project:🚧 What's new: Hardhat 2 → 3
🚧 What's new: Hardhat 2 → 3
Key differences in Hardhat 3:
- compile → build
npx hardhat compileis nownpx hardhat build. This is the big one. The v3 migration guide explicitly shows using thebuildtask. - project init switch
v2 commonly usednpx hardhatornpx hardhat initto bootstrap. In v3 it’snpx hardhat --init.
- keystore helper commands are new
v3’s recommended flow includes a keystore plugin with commands likenpx hardhat keystore set HEDERA_RPC_URLandnpx hardhat keystore set HEDERA_PRIVATE_KEY. These weren’t standard in v2. - Foundry-compatible Solidity tests
In addition to offering Javascript/Typescript integration tests, Hardhat v3 also integrates Foundry-compatible Solidity tests that allows developers to write unit tests directly in Solidity
- Enhanced Network Management
v3 allows tasks to create and manage multiple network connections simultaneously which is a significant improvement over the single, fixed connection available in version 2. This provides greater flexibility for scripts and tests that interact with multiple networks.
HEDERA_RPC_URL, we’ll have https://testnet.hashio.io/api
HEDERA_PRIVATE_KEY, enter the HEX Encoded Private Key for your ECDSA account from the Hedera Portal.
We also need a second private key for testing purposes:
HEDERA_PRIVATE_KEY_2, enter another HEX Encoded Private Key for a second ECDSA account.
Now let’s remove the default contracts and scripts that come with the Hardhat project:
Install Dependencies
Next, install the required dependencies:github:hashgraph/hedera-smart-contracts. This also gets installed at @hashgraph/smart-contracts so we can easily call these contracts from our own contract.
Configure hardhat.config.ts:
hardhat.config.ts
Step 1: Understanding the Architecture
Before diving into code, let’s understand the key concepts that make this rebalancer capacity-aware.The Capacity Problem
When multiple contracts schedule transactions for the same future time:- Network capacity for that second may be exhausted
- Subsequent scheduling attempts fail
- Operations get delayed or fail entirely
The Solution: Capacity-Aware Scheduling
Our rebalancer uses three key Hedera features: 1. hasScheduleCapacity(expirySecond, gasLimit)- Queries if a specific future second can accept a scheduled transaction
- Returns
trueif capacity is available,falseotherwise - Allows contracts to “probe” future availability
- If desired time lacks capacity, try progressively later times: +1s, +2s, +4s, +8s…
- Add random jitter to avoid “thundering herd” where all contracts retry at the same moment
- Spreads load across multiple seconds
- Provides pseudorandom seeds for jitter calculation
- Enables true on-chain randomness without external oracles
- Each contract gets different jitter, naturally distributing load
Scheduling Methods
This tutorial demonstrates three different scheduling approaches:| Method | Use Case | Payer | Loopable |
|---|---|---|---|
scheduleCall | Automated recurring operations | Caller | ✅ Yes |
scheduleCallWithPayer | Recurring with contract as payer | Contract | ✅ Yes |
executeCallOnPayerSignature | One-shot immediate execution | Contract | ❌ No |
How It Works Together
Why This MattersOn traditional EVM chains, you’d need:
- Off-chain service to monitor network congestion
- Manual intervention to adjust timing
- External keeper network that understands capacity
Step 2: Create the Rebalancer Contract
CreateRebalancerCapacityAware.sol in your contracts directory:
contracts/RebalancerCapacityAware.sol
How It Works
- setPayer(): Configures which address will pay for scheduled transactions (typically the contract itself)
-
setSchedulingMethod(): Switches between
scheduleCall(false) andscheduleCallWithPayer(true) - startRebalancing(): Initializes the loop and schedules the first rebalance using capacity-aware logic
-
_findAvailableSecond(): The core capacity-awareness algorithm:
- First checks if desired time has capacity
- If not, tries exponentially increasing delays: +1s, +2s, +4s, +8s…
- Adds random jitter (0 to baseDelay) to each attempt
- Uses Hedera’s PRNG for true on-chain randomness
-
rebalance(): Executed automatically by scheduled transactions:
- Increments counter (in real DeFi, would perform actual rebalancing)
- Schedules next execution using capacity-aware logic
- Creates self-sustaining loop
- stopRebalancing(): Cancels pending schedule and marks loop inactive
-
demoImmediateExecution(): Demonstrates one-shot execution using
executeCallOnPayerSignature - HBAR Requirement: Contract must hold HBAR to pay for all scheduled executions
Step 3: Deploy the Contract
Createdeploy. ts in the scripts directory:
scripts/deploy.ts
Copy the deployed contract address and set it as an environment variable for
the next steps.
verify-bundles/RebalancerCapacityAware/metadata.json file to Hashscan to verify this contract.
Step 4: Configure the Contract
Before starting the rebalancing loop, you need to configure the payer and scheduling method.Set the Contract as Payer
CreatesetPayer.ts in the scripts directory:
scripts/setPayer. ts
Choose a Scheduling Method
You have two options for scheduling. Choose one: Option 1: scheduleCall (default) CreatesetSchedulingMethodScheduleCall.ts:
scripts/setSchedulingMethodScheduleCall.ts
setSchedulingMethodScheduleCallWithPayer.ts:
scripts/setSchedulingMethodScheduleCallWithPayer. ts
Step 5: Start Rebalancing
CreatestartRebalancing.ts in the scripts directory:
scripts/startRebalancing.ts
What’s Happening
startRebalancing(15)calculates desired time:now + 15 seconds- Contract checks:
hasScheduleCapacity(desiredTime, 2_000_000)? - If capacity available → schedules at desired time
- If not → applies exponential backoff with jitter to find available slot
- Emits
RebalancingStartedwith actual scheduled time and scheduling method - After ~15 seconds, network automatically executes
rebalance() rebalance()schedules next execution → creates self-sustaining loop
Step 6: Monitor Rebalancing Operations
CreatemonitorRebalancing. ts to observe the rebalancing loop:
scripts/monitorRebalancing.ts
Rebalance Count increments every ~15 seconds as scheduled transactions execute automatically. When the contract runs out of HBAR, scheduling will fail, and the count will stop increasing however the state remains Active: true until you explicitly stop rebalancing.
Check Contract Config
You can also create a simple script to check the current configuration:scripts/getConfig.ts
View Events on HashScan
Navigate to your contract’s events page to see: RebalanceScheduled Events:- Shows when capacity-aware scheduling found an available slot
chosenTime === desiredTimemeans ideal time had capacitychosenTime > desiredTimemeans backoff was neededschedulingMethodshows which method was used
- Confirms automatic execution by the network
- Tracks total rebalance operations performed
https://hashscan.io/testnet/contract/$CONTRACT_ADDRESS/events
Step 7: Stop Rebalancing
CreatestopRebalancing.ts to halt the loop:
scripts/stopRebalancing.ts
What Happened
stopRebalancing()calleddeleteSchedule(lastScheduleAddress)- Pending scheduled transaction was canceled (best effort)
config.activeset tofalse- Even if a scheduled
rebalance()executes, therequire(config.active)check prevents further scheduling - Loop is fully stopped
Step 8: One-Shot Immediate Execution (Optional)
This demo shows how to useexecuteCallOnPayerSignature for a single, immediate function call. This method is not loopable due to Hedera’s recursion protection.
Create demoImmediateExecution.ts:
scripts/demoImmediateExecution.ts
DemoActionExecuted event emitted.
Step 9: Run Tests (Optional)
You can find both types of tests in the tutorial-hss-rebalancer-capacity-aware repository. You will find the following files: The repository includes both Solidity unit tests and TypeScript integration tests.Solidity Unit Tests (contracts/RebalancerCapacityAware.t.sol)
These tests validate:
- Initial state: Verifies contract deploys with inactive configuration
- Payer configuration: Tests setting and changing the payer address
- Scheduling method switching: Verifies switching between
scheduleCallandscheduleCallWithPayer - Start/stop logic: Confirms only inactive rebalancers can be started and active ones can be stopped
- Configuration validation: Ensures interval must be greater than zero
- HBAR handling: Verifies contract can receive HBAR for funding scheduled operations
- State management: Tests that rebalance count and timestamps are properly maintained
TypeScript Integration Tests (test/RebalancerCapacityAware.ts)
These tests run against Hedera testnet and validate:
- Deployment and funding: Deploys with substantial HBAR balance and validates initial state
- scheduleCall method: Tests automated recurring rebalancing with
scheduleCall - scheduleCallWithPayer method: Tests automated recurring rebalancing with
scheduleCallWithPayer(contract as payer) - executeCallOnPayerSignature: Demonstrates one-shot immediate execution
- deleteSchedule: Verifies schedule deletion via
stopRebalancing - Capacity awareness: Tests that the contract successfully finds available time slots using
hasScheduleCapacity - Input validation: Tests error handling for invalid inputs
- Scheduling method switching: Verifies switching between scheduling methods
Conclusion
You’ve built a sophisticated capacity-aware DeFi rebalancer that demonstrates advanced patterns with Hedera’s Schedule Service! In this tutorial, you learned how to:- Query network capacity using
hasScheduleCapacity() - Implement exponential backoff with randomized jitter
- Use Hedera’s PRNG for true on-chain randomness
- Build self-sustaining loops that automatically reschedule
- Choose between scheduling methods:
scheduleCallvsscheduleCallWithPayer - Handle one-shot execution using
executeCallOnPayerSignature - Handle network congestion gracefully
- Cancel scheduled operations when needed
Key Takeaways
- Capacity-aware scheduling prevents network congestion. Contracts cooperate with the network’s throttling model
- Exponential backoff + jitter distributes load. Avoids “thundering herd” where all contracts compete for the same slot
- True on-chain randomness via PRNG. No external oracles needed for jitter calculation
- Multiple scheduling methods for different use cases. Use
scheduleCallorscheduleCallWithPayerfor recurring operations,executeCallOnPayerSignaturefor one-shots - This level of network awareness doesn’t exist on most EVM chains. Hedera enables truly intelligent on-chain automation
Real-World Applications
This pattern can be extended to:- DeFi Vaults: Automatic portfolio rebalancing based on price oracles
- Liquidity Management: Periodic adjustment of AMM positions
- Treasury Operations: Scheduled fund distributions or buybacks
- Yield Optimization: Regular harvesting and compounding of rewards
- DAO Governance: Time-delayed execution of approved proposals