|
1 | | -Action: `swap` (ExchangeHelper buy/sell) |
| 1 | +Action: `swap` (MentoReserve + Mento exchange via `MentoBroker.swapIn` / `swapOut`) |
2 | 2 |
|
3 | 3 | When to use: |
4 | | -- The user asks to swap, buy GD, sell GD, or convert between tokens handled by the protocol reserve + Uniswap. |
| 4 | +- The user wants to buy `G$` using `cUSD` (`direction = "buy"`). |
| 5 | +- The user wants to sell `G$` to receive `cUSD` (`direction = "sell"`). |
| 6 | +- Execute the swap through Mento directly via `MentoBroker.swapIn` (buy) or `MentoBroker.swapOut` (sell). |
5 | 7 |
|
6 | 8 | Inputs to request (if missing): |
7 | | -- `nameServiceAddress` |
8 | | -- `mode`: `buy` or `sell` |
| 9 | +Common: |
9 | 10 | - `rpcUrl` + `chainId` |
10 | 11 | - `privateKey` (or other signer) for sending the tx |
11 | | -- `targetAddress` (optional; if `0x0000000000000000000000000000000000000000`, outputs go to the signer/`msg.sender`) |
12 | | - |
13 | | -Buy inputs: |
14 | | -- `buyPath` (address[]) |
15 | | -- `tokenAmount` (uint256) |
16 | | -- `minReturn` (uint256) |
17 | | -- `minDAIAmount` (uint256) |
18 | | - |
19 | | -Sell inputs: |
20 | | -- `sellPath` (address[]) |
21 | | -- `gdAmount` (uint256) |
22 | | -- `minReturn` (uint256) |
23 | | -- `minTokenReturn` (uint256) |
24 | | - |
25 | | -Execution: |
26 | | -1) Resolve: |
27 | | - - `exchangeHelperAddress = nameService.getAddress("EXCHANGE_HELPER")` |
28 | | - |
29 | | -2) Approve input tokens (if required): |
30 | | - - If `mode == "buy"` and `buyPath[0] != address(0)` (ERC20 input): |
31 | | - - Approve `ERC20(buyPath[0])` to `exchangeHelperAddress` for `tokenAmount`. |
32 | | - - If `mode == "sell"`: |
33 | | - - Approve `GOODDOLLAR` to `exchangeHelperAddress` for `gdAmount`. |
34 | | - - If `mode == "buy"` and `buyPath[0] == address(0)` (ETH input): |
35 | | - - No ERC20 approval; you must send `msg.value`. |
36 | | - |
37 | | -3) Send tx: |
38 | | - - Path sanity checks before sending: |
39 | | - - For `buy`: when doing a Uniswap-style multi-hop swap, `buyPath` must end with `DAI` (the helper enforces this unless `buyPath[0]` is already `CDAI` or `DAI`). |
40 | | - - For `sell`: if `sellPath` is not the single-token `CDAI` case, `sellPath[0]` must be `DAI` (helper redeems to DAI and then requires Uniswap input to be DAI). |
41 | | - - If `mode == "buy"`: |
42 | | - - Call `ExchangeHelper.buy(buyPath, tokenAmount, minReturn, minDAIAmount, targetAddress)` |
43 | | - - If `buyPath[0] == address(0)` means ETH, include `msg.value = tokenAmount`; otherwise `msg.value = 0`. |
44 | | - - If `mode == "sell"`: |
45 | | - - Call `ExchangeHelper.sell(sellPath, gdAmount, minReturn, minTokenReturn, targetAddress)` |
46 | | - - `msg.value` must be `0`. |
| 12 | + |
| 13 | +Mento config (required): |
| 14 | +- `mentoBrokerAddress` (address) |
| 15 | +- `mentoExchangeProviderAddress` (address) |
| 16 | +- `exchangeId` (bytes32; e.g. the CUSD->G$ exchange id) |
| 17 | + |
| 18 | +Tokens (required): |
| 19 | +- `cUSDAddress` (address) |
| 20 | +- `gdAddress` (address; usually `nameService.getAddress("GOODDOLLAR")`) |
| 21 | + |
| 22 | +Route: |
| 23 | +- `direction` (string) |
| 24 | + - `"buy"`: `cUSDInputAmount -> G$` using `MentoBroker.swapIn` |
| 25 | + - `"sell"`: `G$ -> cUSD` using `MentoBroker.swapOut` |
| 26 | + |
| 27 | +Swap amounts: |
| 28 | +- If `direction = "buy"`: |
| 29 | + - `cUSDInputAmount` (uint256, required; amountIn in token smallest units) |
| 30 | + - `minAmount` (uint256, optional; minimum `G$` expected) |
| 31 | +- If `direction = "sell"`: |
| 32 | + - `cUSDOutputAmount` (uint256, required; exact `cUSD` to receive) |
| 33 | + - `maxGdAmountIn` (uint256, optional; maximum `G$` to spend). If omitted, computed from Mento `getAmountIn` + `slippageBps`. |
| 34 | +- `slippageBps` (uint256, optional; default `200` i.e. 2%) |
| 35 | + |
| 36 | +Recipient: |
| 37 | +- `buyRecipient` (address, optional; default = signer address). `MentoBroker.swapIn/swapOut` pays out to `msg.sender`, so if `buyRecipient` differs you must transfer the received token afterward (`G$` when buying, `cUSD` when selling). |
| 38 | + |
| 39 | +Execution |
| 40 | +1) Pre-check expected amounts (read-only): |
| 41 | + - If `direction = "buy"`: |
| 42 | + - `expectedOut = MentoBroker.getAmountOut(mentoExchangeProviderAddress, exchangeId, cUSDAddress, gdAddress, cUSDInputAmount)` |
| 43 | + - If `direction = "sell"`: |
| 44 | + - `expectedIn = MentoBroker.getAmountIn(mentoExchangeProviderAddress, exchangeId, gdAddress, cUSDAddress, cUSDOutputAmount)` |
| 45 | + - if pre-check reverts, stop and ask for correct `mentoExchangeProviderAddress` + `exchangeId` (or correct token addresses). |
| 46 | + |
| 47 | +2) Choose slippage-bounded limits: |
| 48 | + - If `direction = "buy"`: |
| 49 | + - If `minAmount` provided: use it. |
| 50 | + - Else: `minAmount = expectedOut * (10000 - slippageBps) / 10000`. |
| 51 | + - If `direction = "sell"`: |
| 52 | + - If `maxGdAmountIn` provided: use it. |
| 53 | + - Else: `maxGdAmountIn = expectedIn * (10000 + slippageBps) / 10000`. |
| 54 | + |
| 55 | +3) Approve input token to the broker: |
| 56 | + - If `direction = "buy"`: approve `cUSDInputAmount`. |
| 57 | + - If `direction = "sell"`: approve `maxGdAmountIn`. |
| 58 | + |
| 59 | +4) Execute: |
| 60 | + - If `direction = "buy"`: |
| 61 | + - call `MentoBroker.swapIn(mentoExchangeProviderAddress, exchangeId, cUSDAddress, gdAddress, cUSDInputAmount, minAmount)` |
| 62 | + - let `amountOut` be returned `G$` received. |
| 63 | + - If `direction = "sell"`: |
| 64 | + - call `MentoBroker.swapOut(mentoExchangeProviderAddress, exchangeId, gdAddress, cUSDAddress, cUSDOutputAmount, maxGdAmountIn)` |
| 65 | + - let `amountInUsed` be returned `G$` spent. |
| 66 | + |
| 67 | +5) Deliver to `buyRecipient`: |
| 68 | + - If `buyRecipient` == signer: done. |
| 69 | + - Else: |
| 70 | + - If `direction = "buy"`: `ERC20(gdAddress).transfer(buyRecipient, amountOut)`. |
| 71 | + - If `direction = "sell"`: `ERC20(cUSDAddress).transfer(buyRecipient, cUSDOutputAmount)`. |
| 72 | + |
| 73 | +Post-check (best effort): |
| 74 | +- Confirm the tx did not revert. |
| 75 | +- If `direction = "buy"`: confirm `amountOut >= minAmount`. |
| 76 | +- If `direction = "sell"`: confirm `amountInUsed <= maxGdAmountIn`. |
47 | 77 |
|
48 | 78 | Output to the user: |
49 | 79 | - tx hash |
50 | | -- confirm `buy` vs `sell` |
51 | | -- if possible, interpret `TokenPurchased` / `TokenSold` events when decoding is available |
52 | | - |
| 80 | +- `direction` |
| 81 | +- chosen limits (`minAmount` or `maxGdAmountIn`) |
| 82 | +- amount received (`G$` for buy, `cUSD` for sell) |
| 83 | +- recipient used (`buyRecipient`) |
0 commit comments