ens-budget 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@ Give it a label and a stablecoin amount. It returns the longest renewal that amo
|
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/ens-budget)
|
|
10
10
|
[](https://github.com/wildcardlabs/ens-budget/actions/workflows/ci.yml)
|
|
11
|
-
[](https://bundlejs.com/?q=ens-budget&config=%7B%22esbuild%22%3A%7B%22external%22%3A%5B%22viem%22%5D%7D%7D)
|
|
12
12
|
[](https://www.npmjs.com/package/ens-budget)
|
|
13
13
|
[](https://viem.sh)
|
|
14
|
-
[](./LICENSE)
|
|
15
15
|
|
|
16
16
|
[Install](#install) · [Quick start](#quick-start) · [How it works](#how-it-works) · [Recipes](#recipes) · [API](#api) · [Networks](#networks)
|
|
17
17
|
|
|
@@ -51,10 +51,10 @@ const quote = await quoteRenewal(client, {
|
|
|
51
51
|
quote.duration // 143345079n seconds, about 4 years 6 months
|
|
52
52
|
quote.amount // 25000000n, the exact cost
|
|
53
53
|
quote.tier // { duration: 94608000n, discountBps: 3125 } 3-year rate, 31.25% off
|
|
54
|
-
quote.nextTier // { duration: 189216000n, extraAmount: 2000071n, … } 6 years for $2.
|
|
54
|
+
quote.nextTier // { duration: 189216000n, extraAmount: 2000071n, … } 6 years for $2.01 more
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
To renew, pass a wallet client:
|
|
57
|
+
To renew, pass a viem wallet client with an `account` (using wagmi? see [Renew with wagmi](#recipes)):
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
60
|
import { renewWithBudget } from 'ens-budget'
|
|
@@ -68,13 +68,17 @@ const { hash, quote } = await renewWithBudget(walletClient, {
|
|
|
68
68
|
|
|
69
69
|
## How it works
|
|
70
70
|
|
|
71
|
-
ENS v2 prices renewals in USD per second, by label length, and discounts the whole term once it
|
|
71
|
+
ENS v2 prices renewals in USD per second, by label length, and discounts the whole term once it reaches 2, 3 or 6 years. Because the discount applies to every second of the term, a term just short of a tier can cost more than the tier itself:
|
|
72
72
|
|
|
73
73
|
| `namepass.eth` | Price |
|
|
74
74
|
| --- | --- |
|
|
75
|
-
| 1 year | $8.
|
|
76
|
-
|
|
|
77
|
-
|
|
|
75
|
+
| 1 year | $8.01 |
|
|
76
|
+
| 1 year 364 days | $15.98 |
|
|
77
|
+
| **2 years** | **$14.01** |
|
|
78
|
+
| 5 years 364 days | $32.99 |
|
|
79
|
+
| **6 years** | **$27.01** |
|
|
80
|
+
|
|
81
|
+
Prices are rounded up to the cent. ENS charges exact token units, a fraction of a cent above the round figure (6 years is 27.000071 USDC), so $27.00 buys about 4 years 11 months and $27.01 buys 6 years.
|
|
78
82
|
|
|
79
83
|
Dividing a budget by an annual rate gets this wrong. `quoteRenewal` instead:
|
|
80
84
|
|
|
@@ -89,6 +93,64 @@ Renewals are paid in an ERC-20 token, so the renewer needs an allowance. `renewW
|
|
|
89
93
|
|
|
90
94
|
## Recipes
|
|
91
95
|
|
|
96
|
+
<details>
|
|
97
|
+
<summary><b>Warn when a chosen date costs more than a longer term</b></summary>
|
|
98
|
+
|
|
99
|
+
Apps with a "renew until" date picker can catch terms that fall just short of a tier:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { getPricing, priceOf, solve } from 'ens-budget'
|
|
103
|
+
|
|
104
|
+
const pricing = await getPricing(client, { token }) // once
|
|
105
|
+
|
|
106
|
+
const cost = priceOf(pricing, { label, duration }) // the term the user picked
|
|
107
|
+
const best = solve(pricing, { label, budget: cost })
|
|
108
|
+
|
|
109
|
+
if (best.tier && best.tier.duration > duration) {
|
|
110
|
+
// e.g. "6 years costs $27.01, less than the $32.99 you selected"
|
|
111
|
+
const tierCost = priceOf(pricing, { label, duration: best.tier.duration })
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`priceOf` and `solve` run locally, so this can run on every date change.
|
|
116
|
+
|
|
117
|
+
</details>
|
|
118
|
+
|
|
119
|
+
<details>
|
|
120
|
+
<summary><b>Offer a top-up to the next tier</b></summary>
|
|
121
|
+
|
|
122
|
+
When a budget lands just short of a tier, `quote.nextTier` says how much more reaches it:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const { nextTier } = await quoteRenewal(client, { label, budget: 26_000000n, token })
|
|
126
|
+
// nextTier.extraAmount 1000071n, about $1.01
|
|
127
|
+
// nextTier.extraDuration about 15 more months
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
</details>
|
|
131
|
+
|
|
132
|
+
<details>
|
|
133
|
+
<summary><b>Renew with wagmi</b></summary>
|
|
134
|
+
|
|
135
|
+
`renewWithBudget` needs a viem wallet client with an `account`. With wagmi it is simpler to quote with the public client, build the calls with `prepareRenewal`, and send them through wagmi:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { useAccount, usePublicClient, useSendCalls } from 'wagmi'
|
|
139
|
+
import { prepareRenewal, quoteRenewal } from 'ens-budget'
|
|
140
|
+
|
|
141
|
+
const client = usePublicClient()
|
|
142
|
+
const { address } = useAccount()
|
|
143
|
+
const { sendCallsAsync } = useSendCalls()
|
|
144
|
+
|
|
145
|
+
const quote = await quoteRenewal(client, { label, budget, token })
|
|
146
|
+
const calls = await prepareRenewal(client, quote, { account: address })
|
|
147
|
+
await sendCallsAsync({ calls })
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
For wallets without EIP-5792, send the calls in order with `useSendTransaction`, and wait for the `approve` receipt before sending `renew`.
|
|
151
|
+
|
|
152
|
+
</details>
|
|
153
|
+
|
|
92
154
|
<details>
|
|
93
155
|
<summary><b>Batch approve and renew into one prompt (EIP-5792)</b></summary>
|
|
94
156
|
|
|
@@ -161,7 +223,7 @@ Length is counted in Unicode code points of the label you pass, as ENS counts it
|
|
|
161
223
|
| Function | Returns |
|
|
162
224
|
| --- | --- |
|
|
163
225
|
| `quoteRenewal(client, { label, budget, token, renewers? })` | `Quote`: the longest renewal for the budget, confirmed with ENS. |
|
|
164
|
-
| `renewWithBudget(walletClient, { label, budget, token, referrer?, renewers? })` | `{ hash, quote }` after approving if needed and renewing. |
|
|
226
|
+
| `renewWithBudget(walletClient, { label, budget, token, referrer?, renewers? })` | `{ hash, quote }` after approving if needed and renewing. Needs a wallet client with an `account`. |
|
|
165
227
|
| `prepareRenewal(client, quote, { account, referrer? })` | `Call[]`: `[approve?, renew]` as `{ to, data }`. |
|
|
166
228
|
| `getPricing(client, { token, renewer?, renewers? })` | `Pricing`: oracle rates, discount tiers and token ratio. |
|
|
167
229
|
| `getRenewer(client, { label, renewers? })` | The renewer address for a label, or `null`. |
|
package/package.json
CHANGED