Understanding Payments in Smart Contracts

Introduction to Payments in Smart Contracts

This section aims to provide a comprehensive guide on how smart contracts handle payments, focusing on both receiving and sending tokens.

Note: On the Klever network, it is not possible to simultaneously send KLV and any KDA token. Consequently, you will not find any syntax supporting the transfer of both in either receiving or sending scenarios.


Methods of Receiving Payments

Smart contracts can receive payments in two primary ways:

  1. Directly, akin to regular accounts, without activating any contract code.
  2. Through specific endpoints.

Direct Receipt of Payments

Direct transfers of KLV and KDA tokens to smart contracts operate similarly to transfers to externally owned accounts (EOAs) – the tokens move from one account to another without engaging the VM.

However, a contract's ability to directly receive tokens is governed by a "payable" flag, a part of the code metadata set during the contract's deployment or upgrade.

This design choice stems from the Klever blockchain's approach to direct transfers, which prioritizes simplicity and consistent gas costs, foregoing mechanisms for contracts to respond to such transfers. Consequently, most contracts opt out of accepting direct payments to maintain control over their internal state.

Receipt of Payments via Endpoints

The prevalent method for contracts to accept payments is through endpoints marked with the #[payable(...)] annotation.

Important: The "payable" flag in the code metadata is only relevant to direct transfers. It does not influence token transfers via contract endpoints.

Endpoints designed to accept only KLV should use the #[payable("KLV")] annotation:

#[endpoint]
#[payable("KLV")]
fn accept_KLV(&self) {
	// ...
}

To allow for any type of payment, use #[payable("*")]:

#[endpoint]
#[payable("*")]
fn accept_any_payment(&self) {
	// ...
}

Note: It's possible to hard-code a specific token identifier in the payable attribute, like #[payable("MYTOKEN-123456")]. This is a less common practice, as tokens are typically configured in storage or at runtime.

You can impose additional restrictions on incoming tokens within the endpoint's body by utilizing the call value API, which provides various functions for managing expected payments.


Approaches to Sending Payments

After exploring how contracts receive tokens, let's look at how they can send them, primarily through methods in the self.send() component.

Direct Token Transfers

Contracts can directly send tokens using several API methods:

  • Methods like self.send().direct_kda(to, token, nonce, amount) enable direct token transfers to a specific address.
  • Multiple methods exist for different scenarios, including zero and non-zero amounts, KLV or KDA tokens, single or multiple KDA tokens, and more.

Sending Tokens to Contract Endpoints

To send tokens to contract endpoints, a contract call is necessary. While direct API methods exist for this purpose, it's recommended to create and send a ContractCall. Details on this process can be found in the contract calls reference.

Low-Level API Usage

In cases where the standard methods don't suffice, self.send_raw() offers more granular control for token transfers. This should be a last resort, as detailed in the contract calls page.

Was this page helpful?