-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into cherry-pick-12714-pureChecks-Create-to-de…
…velop
- Loading branch information
Showing
57 changed files
with
2,011 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 165 additions & 0 deletions
165
hedera-node/docs/design/services/token-service/airdrops/token-claim-airdrop.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
# Introduce TokenClaimAirdrop transaction | ||
## Purpose | ||
|
||
We need to add a new functionality that would make it possible for an airdrop receiver to accept a pending airdrop transfer. This would be the only way for a receiver, which hasn't been associated to a given token to accept an airdropped token that has been in pending airdrops state. | ||
|
||
## Goals | ||
|
||
1. Define new `TokenClaimAirdrop` HAPI transaction | ||
2. Implement token claim airdrop transaction handler logic | ||
|
||
## Non-Goals | ||
|
||
- Implement token claim airdrop in system contract functions | ||
|
||
## Architecture | ||
|
||
The implementation related to the new `TokenClaimAirdrop` transaction will be gated behind a `tokens.airdrops.claim.enabled` feature flag. | ||
|
||
### HAPI updates | ||
|
||
Create new transaction type as defined in the HIP: | ||
|
||
```protobuf | ||
/** | ||
* Token claim airdrop<br/> | ||
* Complete one or more pending transfers on behalf of the recipient(s) for each airdrop.<br/> | ||
* The sender MUST have sufficient balance to fulfill the airdrop at the time of claim. If the | ||
* sender does not have sufficient balance, the claim SHALL fail. | ||
* | ||
* Each pending airdrop successfully claimed SHALL be removed from state and SHALL NOT be available | ||
* to claim again. | ||
* | ||
* Each claim SHALL be represented in the transaction body and SHALL NOT be restated | ||
* in the record file.<br/> | ||
* All claims MUST succeed for this transaction to succeed. | ||
*/ | ||
message TokenClaimAirdropTransactionBody { | ||
/** | ||
* A list of one or more pending airdrop identifiers.<br/> | ||
* This transaction MUST be signed by the account referenced in the `receiver_id` for | ||
* each entry in this list. | ||
* <p> | ||
* This list MUST contain between 1 and 10 entries, inclusive.<br/> | ||
* This list MUST NOT have any duplicate entries. | ||
*/ | ||
repeated PendingAirdropId pending_airdrops = 1; | ||
} | ||
/** | ||
* A unique, composite, identifier for a pending airdrop. | ||
* | ||
* Each pending airdrop SHALL be uniquely identified by a PendingAirdropId. | ||
* A PendingAirdropId SHALL be recorded when created and MUST be provided in any transaction | ||
* that would modify that pending airdrop (such as a `claimAirdrop` or `cancelAirdrop`). | ||
*/ | ||
message PendingAirdropId { | ||
/** | ||
* A sending account.<br/> | ||
* This is the account that initiated, and SHALL fund, this pending airdrop.<br/> | ||
* This field is REQUIRED. | ||
*/ | ||
AccountID sender_id = 1; | ||
/** | ||
* A receiving account.<br/> | ||
* This is the ID of the account that SHALL receive the airdrop.<br/> | ||
* This field is REQUIRED. | ||
*/ | ||
AccountID receiver_id = 2; | ||
oneof token_reference { | ||
/** | ||
* A token ID.<br/> | ||
* This is the type of token for a fungible/common token airdrop.<br/> | ||
* This field is REQUIRED for a fungible/common token and MUST NOT be used for a | ||
* non-fungible/unique token. | ||
*/ | ||
TokenID fungible_token_type = 3; | ||
/** | ||
* The id of a single NFT, consisting of a Token ID and serial number.<br/> | ||
* This is the type of token for a non-fungible/unique token airdrop.<br/> | ||
* This field is REQUIRED for a non-fungible/unique token and MUST NOT be used for a | ||
* fungible/common token. | ||
*/ | ||
NftID non_fungible_token = 4; | ||
} | ||
} | ||
``` | ||
|
||
Add new RPC to `TokenService` : | ||
|
||
```protobuf | ||
service TokenService { | ||
// ... | ||
/** | ||
* Claim one or more pending airdrops.<br/> | ||
* This transaction MUST be signed by _each_ account *receiving* an airdrop to be claimed.<br> | ||
* If a Sender lacks sufficient balance to fulfill the airdrop at the time the claim is made, | ||
* that claim SHALL fail. | ||
*/ | ||
rpc claimAirdrop (Transaction) returns (TransactionResponse); | ||
} | ||
``` | ||
|
||
### Fees | ||
|
||
The basic `TokenClaimAirdrop` fee should be proportional to the number of airdrops being claimed in the transaction. | ||
|
||
An update into the `feeSchedule` file would be needed to specify that. | ||
|
||
### Services updates | ||
|
||
- Update `TokenServiceDefinition` class to include the new RPC method definition for claiming airdrops | ||
- Implement new `TokenClaimAirdropHandler` class which should be invoked when the gRPC server handles `TokenClaimAirdrop` transactions. The class should be responsible for: | ||
- Pure checks: validation logic based only on the transaction body itself in order to verify if the transaction is valid one | ||
- Verify that the pending airdrops list contains between 1 and 10 entries, inclusive | ||
- Verify that the pending airdrops list does not have any duplicate entries | ||
- Pre-handle: | ||
- The transaction must be signed by the account referenced by a `receiver_id` for each entry in the pending airdrops list | ||
- Confirm that for the given pending airdrops ids in the transaction there are corresponding pending transfers existing in state | ||
- Check if the sender has sufficient balance to fulfill the airdrop | ||
- Handle: | ||
- Any additional validation depending on config or state i.e. semantics checks | ||
- The business logic for claiming pending airdrops | ||
- We need to create a token association between each `receiver_id` and `token_reference`, future rents for token association slot should be paid by `receiver_id` | ||
- Since we would have the signature of the receiver, even if it's an account with `receiver_sig_required=true`, the claim would implicitly work properly | ||
- Then we should transfer the claimed tokens to each `receiver_id` | ||
- We can dispatch synthetic crypto transfer for this, but we must skip the assessment of custom fees | ||
- In case of a fungible token claim | ||
- Create a synthetic `CryptoTransfer` with the corresponding `sender`, `receiver`, `token` and `amount` based on the `PendingAirdropId` and the corresponding `PendingAirdropValue` | ||
- Then delegate it to the `CryptoTransfer.handler()` to execute the transfer | ||
- In case of an NFT claim | ||
- Create a synthetic `CryptoTransfer` with the corresponding `sender`, `receiver`, `token` and `serial number` based on the based on the `PendingAirdropId` | ||
- Then delegate it to `CryptoTransfer.handler()` to execute the transfer | ||
- Token transfers and associations should be externalized using the `tokenTransferLists` and `automatic_token_associations` fields in the transaction record | ||
- Fees calculation | ||
|
||
### Zero-Balance accounts | ||
|
||
An account with no open auto-association slots can receive airdrops but must send a `TokenClaimAirdrop` transaction, which requires a payer. If the account has zero hbars, then it can still claim the transfer if someone else is willing to pay for that transaction. For example, a Dapp could be the payer on the transaction. Both the Dapp and the account must sign the transaction. | ||
|
||
### Hollow accounts | ||
|
||
Any existing hollow accounts that were created before [HIP-904](https://hips.hedera.com/hip/hip-904) will have no or limited number of `maxAutoAssociations` depending on if they were created with HBAR or token transfer respectively. That means an airdrop of unassociated tokens to such accounts will result in a pending transfer. | ||
Performing `TokenClaimAirdrop` for such hollow account will also complete the account by setting its key which will obtained from the required transaction signature. Completing the hollow account should not modify the `maxAutoAssociations` on the account. That should always be an explicit step by a user. | ||
|
||
## Acceptance Tests | ||
|
||
All of the expected behaviour described below should be present only if the new `TokenClaimAirdrop` feature flag is enabled. | ||
|
||
- Given existing pending airdrop in state when valid `TokenClaimAirdrop` transaction containing entry for the same pending airdrop is performed then the `TokenClaimAirdrop` should succeed resulting in: | ||
- the tokens being claimed should be automatically associated with the `receiver_id` account | ||
- the tokens being claimed should be transferred to the `receiver_id` account | ||
- the pending airdrop should be removed from state | ||
- Given a successful `TokenClaimAirdrop` transaction having a hollow account as `receiver_id` should also complete the account without modifying its `maxAutoAssociations` value | ||
- Given successful `TokenClaimAirdrop` when another `TokenClaimAirdrop` for the same airdrop is performed then the second `TokenClaimAirdrop` should fail | ||
- `TokenClaimAirdrop` transaction with no pending airdrops entries should fail | ||
- `TokenClaimAirdrop` transaction with more than 10 pending airdrops entries should fail | ||
- `TokenClaimAirdrop` transaction containing duplicate entries should fail | ||
- `TokenClaimAirdrop` transaction containing pending airdrops entries which do not exist in state should fail | ||
- `TokenClaimAirdrop` transaction not signed by the account referenced by a `receiver_id` for each entry in the pending airdrops list should fail | ||
- `TokenClaimAirdrop` transaction with a `sender_id` account that does not have sufficient balance of the claimed token should fail |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.