Smart Contract Rent on Hedera – Part 2: How to Pay
Headshot
Jan 13, 2023
by Ed Marquez
Developer Relations Engineer

🚨🚨Smart contract expiry and auto renewal are currently disabled. Smart contracts will not be charged auto renewal fees or expire.🚨🚨

Contracts will pay rent on Hedera starting in March 2023. As covered in the Part 1 article, rent is the recurring payment required for contracts to remain active on the network and is comprised of auto-renewal and storage fees. This article shows how you can get your contracts ready to make rent payments and avoid expiration.

Try It Yourself

You Will Use These Tools

Goals:

  1. Understand the Rent Settings
  2. Define How Rent Will Be Paid
    1. Pay Rent for New and Existing Contracts

1. Understanding the Rent Settings

Every entity on Hedera has the fields expirationTime, autorenewPeriod, and autorenewAccount:

  • The expirationTime is the date and time when the entity expires
  • The autorenewPeriod is the number of seconds by which the entity expiration is extended each auto-renew event
  • The autorenewAccount is the account that will pay for rent

These fields can be set during creation and changed anytime with an update transaction. The next section covers this in more detail with examples.

Check out this answer in the rent Frequently Asked Questions (FAQ) to see an overview of the renewal process.

2. Defining How Rent Will Be Paid

Smart contracts on Hedera can pay for rent in two ways: external funds or contract funds.

2.1 Paying Rent from External Funds (autorenewAccount)

To pay rent for a contract from external funds (another account or contract), specify the autorenewAccount field using .setAutoRenewAccontId(). You can specify this and other rent-relevant fields for newly deployed contracts (using ContractCreateFlow() or ContractCreateTransaction()) and for existing contracts (using ContractUpdateTransaction()).

The sample function in the first tab below deploys a new contract that will be renewed by the account specified in the variable autorenewAcc. Note that the key for that account (autorenewAccKey) must sign the contract creation transaction. If you specify an admin key for the contract, that key must sign the transaction as well (cAdminKey). You also have the option to use .setAutoRenewPeriod() if you wish to specify that property for the contract. Valid renewal windows are between 30 and 92.5 days – a default of 30 days (7,776,000 seconds) is used if a value is not specified.

The function in the second tab updates an existing contract. An admin key must be specified during contract creation for a contract to be mutable. The function updates the autorenewPeriod for the contract from the default of 30 days to the maximum possible value of 8,000,001 seconds (or 92.5 days).

deployContractFcn
  • deployContractFcn
  • updateContractFcn
Code Snippet Background
export async function deployContractFcn(bytecode, params, gasLim, autorenewAcc, autorenewAccKey, cAdminKey, client) {
    const contractCreateTx = new ContractCreateFlow()
        .setBytecode(bytecode)
        .setConstructorParameters(params)
        .setGas(gasLim)
        // .setAutoRenewPeriod(7776000) //  Default: 7776000sec = 90days. [2592000 (30 days) to 8000001 (92.5 days)]
        .setAutoRenewAccountId(autorenewAcc)
        .setAdminKey(cAdminKey);
    const contractCreateSign1 = await contractCreateTx.sign(autorenewAccKey);
    const contractCreateSign2 = await contractCreateSign1.sign(cAdminKey);
    const contractCreateSubmit = await contractCreateSign2.execute(client);
    const contractCreateRx = await contractCreateSubmit.getReceipt(client);
    const contractId = contractCreateRx.contractId;
    const contractAddress = contractId.toSolidityAddress();
    return [contractId, contractAddress];
}
export async function updateContractFcn(cId, cAdminKey, client) {
    const contractUpdateTx = new ContractUpdateTransaction()
        .setContractId(cId)
        .setAutoRenewPeriod(8000001) //  Default: 7776000sec = 90days. [2592000 (30 days) to 8000001 (92.5 days)]
        // .setAutoRenewAccountId(autorenewAcc);
        // .setContractExpirationTime(newExpirationTime);
        .freezeWith(client);
    const contractUpdateSign = await contractUpdateTx.sign(cAdminKey);
    const contractUpdateSubmit = await contractUpdateSign.execute(client);
    const contractUpdateRec = await contractUpdateSubmit.getRecord(client);
    return contractUpdateRec;
}

You can see an example that uses these functions in index.js in this GitHub repository. Below is the console output of that index.js file.

Console Output:

STEP 1 ===================================
- Creating Alice's account...
- Alice's account: https://hashscan.io/testnet/account/0.0.49297924
 
STEP 2 ===================================
- Deploying contract autorenewed by Alice...
- Contract ID: 0.0.49297928
- Contract ID in Solidity address format: 0000000000000000000000000000000002f03a08
- Get details from mirror node:
- REST API: https://testnet.mirrornode.hedera.com/api/v1/contracts/0.0.49297928
- Explorer: https://hashscan.io/testnet/contract/0.0.49297928
 
STEP 3 ===================================
- Updating contract's autorenew period to 92.5 days...
- Contract update status: SUCCESS
- Get details from mirror node:
- REST API: https://testnet.mirrornode.hedera.com/api/v1/transactions/0.0.2520793-1673634517-367346598
- Explorer: https://hashscan.io/testnet/transaction/1673634526.399625003?tid=0.0.2520793-1673634517-367346598
 
====================================================
🎉🎉 THE END - NOW JOIN: https://hedera.com/discord
===================================================


2.2 Paying Rent from Contract funds

If the autorenewAccount is null, invalid, or has an empty balance, then the entity will try to pay for the auto-renew itself (if the entity is an account or smart contract containing HBAR).

If the contract will pay for its own rent, then it needs to be able to hold and receive HBAR. These two tutorials show how you can send HBAR to contracts using the Hedera SDKs and Solidity:

With the SDK, you can simply do a TransferTransaction() to send HBAR to contracts – this doesn’t require having payable functions or receive() or fallback() functions. This approach is simple and could be suitable if you want to enable users of your contracts to easily make donations.

With Solidity, you can send HBAR to your contracts with fallback(), receive(), or payable functions. The transfer, send, and call methods also work. These options can help you implement a funding approach for your contracts that is fee-based – whether it’s a fixed or dynamic fee, this article explores some of those ideas.

This answer in the rent Frequently Asked Questions (FAQ) also covers how rent is paid for all scenarios involving external and/or contract funds.

Summary

Now you know how to pay rent for newly deployed and existing smart contracts on Hedera. With the approaches covered in this article, you can implement various ways to fund your contracts, from donation-based to fixed or dynamic fees.

Continue Learning