Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[KIP-247] Gasless Transaction #47

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
186 changes: 186 additions & 0 deletions KIPs/kip-247.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
---
kip: 247
title: Gasless Transaction
author: Ian (@ian0371) and Ollie (@blukat29)
discussions-to: TBU
status: Draft
type: Core
created: 2025-02-18
---

## Abstract

This KIP introduces Gasless Transaction (GaslessTx) where users can swap whitelisted fungible tokens into KAIA without possessing any KAIA.

## Motivation

For users who have onboarded onto KAIA from another blockchain via a bridge, it is possible that they do not possess any KAIA tokens and hold only fungible tokens from the bridged assets.
These users will be unable to perform any on-chain actions unless they acquire KAIA through alternative channels.
This limitation effectively restricts their ability to engage with decentralized applications, execute transactions, or participate in any protocol activities within the KAIA ecosystem.

To enhance the user experience for those, this KIP introduces a concept of gasless transaction (GaslessTx) where transactions with a specific pattern is recognized as the GaslessTx.
Upon detection of GaslessTx, the block proposer may lend the user KAIA to facilitate the GaslessTx execution.
A gasless swap from Token to KAIA shall pay back the lent amount.

## Specification

### Definition of GaslessTx

There are two types of GaslessTx: GaslessApproveTx, and GaslessSwapTx.

#### GaslessApproveTx

A GaslessApproveTx must meet all the following conditions to be inserted to `txpool.queue`:

- A1: `GaslessApproveTx.to` is a whitelisted ERC-20 token.
- A2: `GaslessApproveTx.data` is `approve(spender, amount)`.
- A3: `spender` is a whitelisted `GaslessSwapRouter`.
- A4: `amount` is a nonzero.

(Note that above statements can be verified solely through a static validation of a transaction.)

A GaslessApproveTx must meet all the following conditions to be promoted to `txpool.pending`:

- AP1: GaslessApproveTx is followed by a GaslessSwapTx of the same sender and the `GaslessSwapTx` can be promoted to `txpool.pending`.

#### GaslessSwapTx

A `GaslessSwapTx` must meet all the following conditions to be inserted to `txpool.queue`:

- S1: `GaslessSwapTx.to` is a whitelisted `GaslessSwapRouter`.
- S2: `GaslessSwapTx.data` is `swapForGas(token, amountIn, amountOut, amountRepay)`.
- S3. `token` is a whitelisted ERC20 token.

(Note that above statements can be verified solely through a static validation of a transaction.)

A `GaslessSwapTx` must meet all the following conditions to be promoted to `txpool.pending`:

- SP1: (If GaslessApproveTx exists in `txpool.queue`) `GaslessApproveTx.to=token`.
- SP2: (If GaslessApproveTx exists in `txpool.queue`) `GaslessApproveTx.data.amount>=amountIn`.
- SP3: `amountRepay` is the correct value.
- (If GaslessApproveTx exists in `txpool.queue`) `amountRepay = CalcRepayAmount(GaslessApproveTx, GaslessSwapTx)`.
- (otherwise) `amountRepay = amountRepay(GaslessSwapTx)`.
- `amountRepay(GaslessApproveTx, GaslessSwapTx) = R1 + R2 + R3` and `amountRepay(GaslessSwapTx) = R1 + R3` where
- `R1 = LendTx.Fee() = SwapTx.GasPrice() * 21000`
- `R2 = ApproveTx.Fee()` (if exists)
- `R3 = SwapTx.Fee()`

While GaslessApproveTx must be followed by with GaslessSwapTx in order to be promoted, GaslessSwapTx can exist by itself.

### Definition of LendTx

Upon detection of a GaslessTx (either GaslessApproveTx or GaslessSwapTx), the block proposer shall inject a transaction, denoted by LendTx, which transfers KAIA to the GaslessTx sender. LendTx must meet all the following requirements:

- L1: `LendTx.type` is 0x7802, a Ethereum dynamic fee transaction type.
- L2: `LendTx.from` is the proposer itself.
- L3: `LendTx.to` is `GaslessSwapTx.from`
- L4: `LendTx.value` is `amountLend`
- `amountLend` is `R2 + R3` (from aforementioned `amountRepay` definition).

### GaslessSwapRouter

GaslessSwapRouter is a smart contract responsible for token swap and repayment. It must support the following interface:

```
interface IKIP247 {
function swapForGas(address token, uint256 amountIn, uint256 minAmountOut, uint256 amountRepay) external;
function addToken(address token, address dex) external;
function removeToken(address token) external;

function claimCommission() external;
function updateCommissionRate(uint256 _commissionRate) external;

// view functions
function dexAddress(address token) external view returns (address dex);
function getAmountIn(address token, uint amountOut) external view returns (uint amountIn);
}
```

`swapForGas()` must ensure that all the following conditions are satisfied:

- R1: Sender has enough tokens. That is, `token.balanceOf(msg.sender) >= amountIn`.
- R2: Token is whitelisted and has a corresponding DEX address other than zero.
- R3: `amountReceived >= minAmountOut >= amountRepay` where `amountReceived` is the swap output.

`swapForGas()` must distribute the swap output (`amountReceived`) as follows:

- The block proposer (`block.coinbase`) receives `amountRepay`.
- User receives `(amountReceived - amountRepay) * (1 - commissionRate)`.
- The commission `(amountReceived - amountRepay) * commissionRate` is stored in the contract for later claim.

### TxPool Policy Updates

#### GaslessTx Validation (validateTx)

To prevent GaslessTx to be discarded, the validation logic at `txpool.queue` insertion needs to detect GaslessTx and skip the account balance check.

```
// txpool.validateTx()
if ...
else: // if tx is NOT feeDelegatedTx
if senderBalance.Cmp(tx.Cost()) < 0:
if tx is GaslessTx:
validation ok
else:
insufficientFund error
```

#### Promoting GaslessTx (promoteExecutables)

GaslessApproveTx cannot be executed unless the corresponding GaslessSwapTx from the same sender is already in the transaction pool.
Conversely, if the token has not been approved, GaslessSwapTx cannot be executed before GaslessApproveTx.
In such cases, both transactions need to be promoted simultaneously.

```
// txpool.promoteExecutables()
if tx is GaslessApproveTx:
if GaslessSwapTx is in queue:
promote GaslessApproveTx and GaslessSwapTx to pending
else:
push GaslessApproveTx to queue

if tx is GaslessSwapTx:
if tx is GaslessApproveTx is in queue:
promote GaslessApproveTx and GaslessSwapTx to pending
else if GaslessSwapTx.nonce == getNonce(user):
push GaslessApproveTx to pending
else if GaslessSwapTx.nonce == getNonce(user) + 1:
promote GaslessSwapTx to queue
```

#### Transaction Bundling

This KIP implements `TxBundlingModule` specified in [KIP-245](https://kips.kaia.io/KIPs/kip-245). These are the possible bundles:

- LendTx - GaslessApproveTx - GaslessSwapTx
- LendTx - GaslessSwapTx

```
ExtractTxBundles(txs, prevBundles):
if GaslessTx is disabled:
return nothing

filter ApproveTx, SwapTx from txs
move ApproveTx (if exists) before SwapTx
inject LendTx before ApproveTx if exists, otherwise before SwapTx
```

## Rationale

### Disabling GaslessTx

If many consensus nodes disabled GaslessTx feature, users may experience increased transaction latency.
However, as long as there are still nodes supporting GaslessTx, the transactions will eventually be executed.
Also, because this feature is enabled by default, few consensus nodes are expected to disable it.

## Backward Compatibility

This does not affect the backward compatibility because this does not involve hardfork.

## References

- [KIP-245](https://kips.kaia.io/KIPs/kip-245)

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Loading