-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ECO-2067] Add tier-based rewards (#200)
- Loading branch information
Showing
3 changed files
with
253 additions
and
94 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,55 @@ | ||
<!--- | ||
cspell:word undergassing | ||
cspell:word permissionlessly | ||
--> | ||
# `emojicoin-dot-fun` rewards | ||
|
||
# `EmojicoinDotFunRewards` | ||
This package contains an overloaded version of the `swap` function for | ||
`emojicoin-dot-fun`, `swap_with_rewards`, which gives users an opportunity for a | ||
reward based on the amount of integrator fees they pay for their swap. | ||
|
||
This package provides an overloaded swap function that randomly rewards a fixed | ||
percentage of swaps that exceed an arbitrary amount of volume. Funds are | ||
autonomously disbursed from a resource account with an APT vault that can be | ||
topped off permissionlessly. | ||
The rewards vault can be loaded up via the `fund_tiers` function. | ||
|
||
Per the [undergassing docs], one strategy to mitigate undergassing attacks is to | ||
make the most preferred path cost the most gas. Hence, here it is ensured that | ||
the winning path requires the most gas per the final logical branch: | ||
Rewards distributions are random, and based on a probabilistic threshold | ||
determined by the number of nominal rewards distributions expected for a given | ||
nominal volume amount. See `reward_tiers` for more. | ||
|
||
```move | ||
let result = randomness::u64_range(0, WIN_PERCENTAGE_DENOMINATOR); | ||
if (result < WIN_PERCENTAGE_NUMERATOR) { | ||
// If user wins ... | ||
``` | ||
For ease of parameter modeling, named constants use values in `APT`, which are | ||
converted to octas internally. | ||
|
||
## Publish commands | ||
|
||
To view the bytecode result: | ||
Set variables: | ||
|
||
```sh | ||
aptos move compile --dev | ||
aptos move disassemble --bytecode-path \ | ||
build/EmojicoinDotFunRewards/bytecode_modules/emojicoin_dot_fun_rewards.mv | ||
EMOJICOIN_DOT_FUN=0xaaa... | ||
INTEGRATOR=0xbbb... | ||
REWARDS=0xccc... | ||
PROFILE=my-profile | ||
``` | ||
|
||
Then inside `build/EmojicoinDotFunRewards/bytecode_modules`, open | ||
`emojicoin_dot_fun_rewards.asm` and note: | ||
Publish: | ||
|
||
```asm | ||
B4: | ||
56: LdU64(0) | ||
57: LdConst[6](U64: [16, 39, 0, 0, 0, 0, 0, 0]) | ||
58: Call randomness::u64_range(u64, u64): u64 | ||
59: LdConst[7](U64: [231, 3, 0, 0, 0, 0, 0, 0]) | ||
60: Lt | ||
61: BrFalse(85) | ||
```sh | ||
NAMED_ADDRESSES=$( | ||
printf "%s,%s,%s" \ | ||
"emojicoin_dot_fun=$EMOJICOIN_DOT_FUN" \ | ||
"integrator=$INTEGRATOR" \ | ||
"rewards=$REWARDS" | ||
) | ||
aptos move publish \ | ||
--assume-yes \ | ||
--named-addresses $NAMED_ADDRESSES \ | ||
--profile $PROFILE | ||
``` | ||
|
||
Here, the `false` (losing) branch is essentially an instant return, while the | ||
`true` (winning) branch requires additional logic. | ||
## Fund the vault | ||
|
||
Note that even if the `BrFalse` instruction were to be exceptionally expensive | ||
for the `false` branch, it would still not be able to make the losing path more | ||
expensive in the general case, because the winning path *also* has a `BrFalse` | ||
statement where the preferred case is the `false` outcome, specifically: | ||
|
||
```move | ||
let reward_amount = if (vault_balance < REWARD_AMOUNT_IN_OCTAS) vault_balance | ||
else REWARD_AMOUNT_IN_OCTAS; | ||
```sh | ||
REWARDS=0xaaa... | ||
PROFILE=my-profile | ||
N_REWARDS_TO_FUND_PER_TIER="u64:[1500,500,200,50,5,1]" | ||
``` | ||
|
||
Hence the winning path is necessarily more expensive than the losing path | ||
because it contains all of the same instructions as the losing path, and more, | ||
except in the extreme hypothetical edge case where: | ||
|
||
1. `BrFalse` for the `false` branch is set absurdly high in a gas schedule | ||
update, such that its execution cost vastly exceeds all other instructions in | ||
the winning path combined. | ||
1. The user is the last lottery winner, sweeping a vault that has less than the | ||
single rewards amount inside. | ||
|
||
Yet even this can issue can be mitigated, by simply filling up the vault with | ||
an integer number of standard reward amounts, because then the lottery will | ||
never evaluate due to this statement: | ||
|
||
```move | ||
if (vault_balance == 0) return; | ||
```sh | ||
aptos move run \ | ||
--args $N_REWARDS_TO_FUND_PER_TIER \ | ||
--function-id $REWARDS::emojicoin_dot_fun_rewards::fund_tiers \ | ||
--profile $PROFILE | ||
``` | ||
|
||
[undergassing docs]: https://aptos.dev/en/build/smart-contracts/randomness#undergasing-attacks-and-how-to-prevent |
Oops, something went wrong.