Skip to content

Commit

Permalink
[ECO-2067] Add tier-based rewards (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
alnoki authored Aug 18, 2024
1 parent 91a9119 commit 8f84673
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 94 deletions.
19 changes: 19 additions & 0 deletions src/move/emojicoin_dot_fun/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,31 @@ needs to have at least 2 APT to be able to publish, even if it only costs 1 APT.

## Signer-signer publication

Set variables:

```sh
EMOJICOIN_DOT_FUN=0xaaa...
PROFILE=my-profile...
```

Fund with faucet as applicable:

```sh
# Run this command twice.
aptos account fund-with-faucet \
--account $EMOJICOIN_DOT_FUN \
--profile $PROFILE
```

Publish the package:

```sh
aptos move publish \
--assume-yes \
--included-artifacts=none \
--max-gas 2000000 \
--named-addresses emojicoin_dot_fun=$EMOJICOIN_DOT_FUN \
--profile $PROFILE \
--override-size-check
```

Expand Down
98 changes: 39 additions & 59 deletions src/move/rewards/README.md
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
Loading

0 comments on commit 8f84673

Please sign in to comment.