Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
@bananapus/buyback-hook
Advanced tools
When a Juicebox project that uses the buyback hook is paid, it checks whether buying tokens in a Uniswap pool or paying the project as usual would yield more tokens for the payer. If buying tokens in the pool would yield more tokens, the payment is routed
When a Juicebox project that uses the buyback hook is paid, it checks whether buying tokens in a Uniswap pool or paying the project as usual would yield more tokens for the payer. If buying tokens in the pool would yield more tokens, the payment is routed there. Otherwise, the payment is sent to the project as usual. Either way, the project's reserved rate applies.
The buyback hook works with any Juicebox terminal and checks the Uniswap pool specified by the project's owner.
If you're having trouble understanding this contract, take a look at the core protocol contracts and the documentation first. If you have questions, reach out on Discord.
For npm
projects (recommended):
npm install @bananapus/buyback-hook
For forge
projects (not recommended):
forge install Bananapus/nana-buyback-hook
Add @bananapus/buyback-hook/=lib/nana-buyback-hook/
to remappings.txt
. You'll also need to install nana-buyback-hook
's dependencies and add similar remappings for them.
nana-buyback-hook
uses the Foundry development toolchain for builds, tests, and deployments. To get set up, install Foundry:
curl -L https://foundry.paradigm.xyz | sh
You can download and install dependencies with:
forge install
If you run into trouble with forge install
, try using git submodule update --init --recursive
to ensure that nested submodules have been properly initialized.
Some useful commands:
Command | Description |
---|---|
forge build | Compile the contracts and write artifacts to out . |
forge fmt | Lint. |
forge test | Run the tests. |
forge build --sizes | Get contract sizes. |
forge coverage | Generate a test coverage report. |
foundryup | Update foundry. Run this periodically. |
forge clean | Remove the build artifacts and cache directories. |
To learn more, visit the Foundry Book docs.
For convenience, several utility commands are available in package.json
.
Command | Description |
---|---|
npm test | Run local tests. |
npm run test:fork | Run fork tests (for use in CI). |
npm run coverage:lcov | Generate an LCOV test coverage report. |
npm run deploy:ethereum-mainnet | Deploy to Ethereum mainnet |
npm run deploy:ethereum-sepolia | Deploy to Ethereum Sepolia testnet |
npm run deploy:optimism-mainnet | Deploy to Optimism mainnet |
npm run deploy:optimism-testnet | Deploy to Optimism testnet |
This contract is both a data hook and a pay hook. Data hooks receive information about a payment and put together a payload for the pay hook to execute.
Juicebox projects can specify a data hook in their JBRulesetMetadata
. When someone attempts to pay or redeem from the project, the project's terminal records the payment in the terminal store, passing information about the payment to the data hook in the process. The data hook responds with a list of payloads – each payload specifies the address of a pay hook, as well as some custom data and an amount of funds to send to that pay hook.
Each pay hook can then execute custom behavior based on the custom data (and funds) they receive.
pay(...)
function calls this buyback hook (as a data hook) to determine whether the swap should be executed or not. It makes this determination by considering the information that was passed in, information about the pool, and the project's current rules.afterPayRecordedWith(...)
method, which will wrap the ETH (to wETH), execute the swap, burns the token it received, and mints them again (it also mints tokens for any funds which weren't used in the swap, if any). This burning/re-minting process allows the buyback hook to apply the reserved rate and respect the caller's preferClaimedTokens
preference.addToBalanceOf
to send the funds to the project.Tips for project owners using the buyback hook.
Every time the buyback hook chooses the swap route, a Uniswap trade will be executed, making payers vulnerable to MEV attacks.
To mitigate MEV attacks, frontend clients should provide a reasonable minimum quote, and the TWAP parameters should be carefully set – these parameters are used to calculate a default minimum quote when the payer/client doesn't provide one.
You can also avoid MEV attacks by using the Flashbots Protect RPC for transactions which trigger the buyback hook. You can add this RPC to your wallet on protect.flashbots.net. If you're using a multisig wallet (like a Gnosis Safe), make sure that the last signer signs and executes at the same time while using the Flashbots Protect RPC. For more information on mitigating MEV from your Gnosis Safe, see this article.
As the project owner, you have two parameters at your disposal to protect payers: the TWAP window and the maximum slippage tolerance. See TWAP Basics for an explanation.
You'll also want to keep the pool's cardinality in mind. This is the number of recent transactions the Uniswap pool keeps track of for calculating the TWAP. If the cardinality is only 1 (the default), then the TWAP will only take the most recent trade into account for calculations. Anyone can increase the pool's cardinality by calling the pool's increaseObservationCardinalityNext(...)
function.
For an overview of TWAP risks, see this article. Some other helpful resources:
JBConstants.NATIVE_TOKEN
: 0x000000000000000000000000000000000000EEEe
.fee
is a uint24
with the same representation as in Uniswap's contracts (basis points with 2 decimals): a 0.01% fee is 100
, a 0.05% fee is 500
, a 0.3% fee is 3000
, and a 1% fee is 10000
.When you trade tokens on Uniswap, you must provide a minimum acceptable price for your trade to protect against excessive price movement (also called "slippage"). If the price moves unfavourably beyond this slippage tolerance, your trade will not be executed, protecting you from receiving a worse deal than you were expecting.
The buyback hook allows payers (or frontend clients) to provide a minimum acceptable return from their trade, and the hook will only execute the trade if it can provide that return – if it can't, the terminal's default behavior takes over. In most cases, this means the payment will go to the project that the hook is associated with.
But if the payer (or frontend client) does not provide a minimum acceptable return, the buyback hook must calculate a fair minimum on its own. On Uniswap, the current price is called a "spot price". This can be dangerous to rely on, because the price can move around quickly. To solve this problem, Uniswap v3 exposes a smoothed-out price called a TWAP, or a time-weighted average price. This is calculated by taking the geometric mean of the price over a window of time, which you can learn more about here.
The buyback hook allows each project to specify a time window (period of time) over which to calculate the TWAP. It also allows each project to specify a "TWAP slippage tolerance". This is the same as the minimum acceptable price above: with a 5% TWAP slippage tolerance, the transaction will revert to the terminal's default behavior if the expected return is more than 5% worse than the TWAP price over the window.
setPoolFor(...)
. If they migrate to a new exchange, this hook won't work.FAQs
The buyback hook allows a project to route incoming payments to a Uniswap pool for their project's token if doing so would yield more tokens for the payer.
The npm package @bananapus/buyback-hook receives a total of 0 weekly downloads. As such, @bananapus/buyback-hook popularity was classified as not popular.
We found that @bananapus/buyback-hook demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.