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

Add HIP-904 Frictionless Airdrops design #8127

Merged
merged 12 commits into from
May 9, 2024
182 changes: 182 additions & 0 deletions docs/design/frictionless-airdrops.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# HIP-904 Frictionless Airdrops

## Purpose

[HIP-904](https://hips.hedera.com/hip/hip-904) enables frictionless airdrops of both fungible and non-fungible tokens by removing the requirement to pre-associate tokens with the receiver’s account.

## Goals

- Ingest the following transactions and persist to the database:
- `TokenAirdrop`
- `TokenCancelAirdrop`
- `TokenClaimAirdrop`
- `TokenReject`
- Expose Pending Airdrop information via the Java REST API

## Non-Goals

- Enhance gRPC APIs with Pending Airdrop information
- Enhance Web3 APIs with Pending Airdrop information
edwin-greene marked this conversation as resolved.
Show resolved Hide resolved

## Architecture

### Database

#### Pending Airdrops

```sql
create type airdrop_state as enum ('PENDING', 'CANCELLED', 'CLAIMED');

create table if not exists token_airdrop
(
amount bigint,
receiver_account_id bigint not null,
sender_account_id bigint not null,
serial_number bigint,
xin-hedera marked this conversation as resolved.
Show resolved Hide resolved
state airdrop_state not null default 'PENDING',
timestamp_range int8range not null,
token_id bigint not null
);
xin-hedera marked this conversation as resolved.
Show resolved Hide resolved

create index if not exists token__airdrop on token_airdrop (sender_account_id, receiver_account_id, token_id, serial_number);
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

create table if not exists token_airdrop_history
(
like token_airdrop including defaults
);

create index if not exists token_airdrop_history__token_serial_lower_timestamp
on token_airdrop_history using gist (timestamp_range);
```

edwin-greene marked this conversation as resolved.
Show resolved Hide resolved
### Importer

#### Pending Airdrop Parsing

When parsing pending airdrops,

- Persist airdrops to the `token_airdrop` table.
- If a `TokenAirdrop` transaction occurs when an entry already exists for a fungible token in the `PENDING` state, an entry should be made in the `token_airdrop_history` table (just as with a change of state to `CANCELLED` or `CLAIMED`), and the `token_airdrop` table should be updated with `amount` set to the sum of the existing amount and the new amount.
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

#### Domain

- Add an `TokenAirdrop` domain object with the same fields as the schema.
- Add an `TokenCancelAirdrop` domain object with the same fields as the schema.
- Add an `TokenClaimAirdrop` domain object with the same fields as the schema.
xin-hedera marked this conversation as resolved.
Show resolved Hide resolved

#### Entity Listener

- Add `onCancelAirdrop` to handle setting the `state` to `CANCELLED`. Updates the `token_airdrop` table and the `token_airdrop_history` table.
- Add `onClaimAirdrop` to handle setting the `state` to `CLAIMED`. Updates the `token_airdrop` table and the `token_airdrop_history` table.
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved
- Add `onTokenAirdrop` to handle inserts to the `token_airdrop` table.

#### Transaction Handlers

- Add `TokenAirdropTransactionHandler` which will add a new entry to the `token_airdrop` table with the default state of `PENDING`.
- Add `TokenCancelAirdropTransactionHandler` which will set the state of the airdrop to `CANCELLED`
- Add `TokenClaimAirdropTransactionHandler` which will set the state of the airdrop to `CLAIMED`
- Add `TokenRejectTransactionHandler` which will be similar to `CryptoTransferTransactionHandler`.

#### Support unlimited Max Automatic Token Associations

- Add test(s) for the `-1` value for `maxAutomaticTokenAssociations`.

### WEB3
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

#### Support unlimited Max Automatic Token Associations

- Update Web3 `CryptoOpsUsage` and `SyntheticTxnFactory` to handle `-1` values for `maxAutomaticTokenAssociations`.
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

### REST API

- Add the new endpoints to Java REST.
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

#### List of outstanding airdrops sent by senderIdOrEvmAddress which have not been claimed by recipients
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

`/api/v1/accounts/{senderIdOrEvmAddress}/airdrops/outstanding`
edwin-greene marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"airdrops": [
{
"amount": 333,
"receiver_id": "0.0.999",
"sender_id": "0.0.222",
"serial_number": null,
"token_id": "0.0.111"
},
{
"amount": 555,
"receiver_id": "0.0.999",
"sender_id": "0.0.222",
"serial_number": null,
"token_id": "0.0.444"
},
{
"amount": null,
"receiver_id": "0.0.999",
"sender_id": "0.0.222",
"serial_number": 888,
"token_id": "0.0.666"
}
],
"links": {
"next": null
}
}
```

Optional Filters

- `limit` - The maximum number of airdrops to return in the response. Defaults to `25` with a max of `100`.
- `order` - The direction to sort the items by `token_id` in the response. Can be `asc` or `desc` with a default of `asc`.
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved
- `receiver.id` - The receiver account the outstanding airdrop was intended for.
- `serialnumber` - The specific serial number associated with airdrop. Supports `eq`, `gt`, `gte`, `lt`, and `lte` operators. Only one occurrence is allowed.
- `token.id` - The token ID this airdrop is associated with. Supports `eq`, `gt`, `gte`, `lt`, and `lte` operators. Only one occurrence is allowed.
xin-hedera marked this conversation as resolved.
Show resolved Hide resolved

#### List of pending airdrops that receiverIdOrEvmAddress has not yet claimed

`/api/v1/accounts/{receiverIdOrEvmAddress}/airdrops/pending`

```json
{
"airdrops": [
{
"amount": 333,
"receiver_id": "0.0.999",
"sender_id": "0.0.222",
"serial_number": null,
"token_id": "0.0.111"
},
{
"amount": 555,
"receiver_id": "0.0.999",
"sender_id": "0.0.222",
"serial_number": null,
"token_id": "0.0.444"
},
{
"amount": null,
"receiver_id": "0.0.999",
"sender_id": "0.0.222",
"serial_number": 888,
"token_id": "0.0.666"
}
],
"links": {
"next": null
}
}
```

Optional Filters

- `limit` - The maximum number of airdrops to return in the response. Defaults to `25` with a max of `100`.
- `order` - The direction to sort the items by `token_id` in the response. Can be `asc` or `desc` with a default of `asc`.
- `sender.id` - The sender account that initiated the pending airdrop.
- `serialnumber` - The specific serial number associated with airdrop. Supports `eq`, `gt`, `gte`, `lt`, and `lte` operators. Only one occurrence is allowed.
- `token.id` - The token ID this airdrop is associated with. Supports `eq`, `gt`, `gte`, `lt`, and `lte` operators. Only one occurrence is allowed.

steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved
## Non-Functional Requirements
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved
steven-sheehy marked this conversation as resolved.
Show resolved Hide resolved

- Ingest new transaction types at the same rate as consensus nodes