-
Notifications
You must be signed in to change notification settings - Fork 12
/
deploy-kandel.js
157 lines (131 loc) 路 5.86 KB
/
deploy-kandel.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Load environment variables (RPC_URL and PRIVATE_KEY) from the .env file
require("dotenv").config();
// Import Mangrove and KandelStrategies APIs
const {
Mangrove,
KandelStrategies,
ethers,
} = require("@mangrovedao/mangrove.js");
// Create a wallet with a provider to interact with the chain
const provider = new ethers.providers.WebSocketProvider(process.env.LOCAL_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
// Connect the API to Mangrove
const mgv = await Mangrove.connect({ signer: wallet });
// Choose a market
const market = await mgv.market({
base: "WETH",
quote: "USDT",
tickSpacing: 1,
});
// Initialize KandelStrategies for strategy management
const kandelStrategies = new KandelStrategies(mgv);
// Retrieve default configuration for the selected market
const config = kandelStrategies.configuration.getConfig(market);
// Create a distribution generator for the selected market
const distributionGenerator = kandelStrategies.generator(market);
// Get the minimum required base and quote amounts per offer for the market
const minBasePerOffer = await kandelStrategies.seeder.getMinimumVolume({
market,
offerType: "asks",
onAave: false,
});
const minQuotePerOffer = await kandelStrategies.seeder.getMinimumVolume({
market,
offerType: "bids",
onAave: false,
});
// Calculate a candidate distribution with the recommended minimum volumes given the price range and a price ratio of roughly 1% (it gets converted to an offset in ticks between prices, and some precision is lost)
// The price points are generated outwards from the mid price, and the default step size for the market is used.
const minDistribution =
await distributionGenerator.calculateMinimumDistribution({
distributionParams: {
minPrice: 900,
maxPrice: 1100,
priceRatio: 1.01,
midPrice: 1000,
generateFromMid: true,
stepSize: config.stepSize,
},
minimumBasePerOffer: minBasePerOffer,
minimumQuotePerOffer: minQuotePerOffer,
});
// Output information about the minimum distribution
const minVolumes = minDistribution.getOfferedVolumeForDistribution();
console.log("Number of price points:", minDistribution.pricePoints);
console.log("Minimum base volume:", minVolumes.requiredBase.toString());
console.log("Minimum quote volume:", minVolumes.requiredQuote.toString());
// Recalculate the distribution based on desired base and quote amounts, which should be at least the recommended.
const finalDistribution =
await distributionGenerator.recalculateDistributionFromAvailable({
distribution: minDistribution,
availableBase: 3,
availableQuote: 3000,
});
const offeredVolumes = finalDistribution.getOfferedVolumeForDistribution();
// Inspect the final distribution's offers - their raw ticks are shown along with their price - and initially dead offers can be seen with 0 gives.
console.log(finalDistribution.getOffersWithPrices());
// Prepare seed data for deploying a Kandel instance
const seed = {
onAave: false,
market,
liquiditySharing: false,
};
// Deploy a Kandel instance with the specified seed data (the offers are later populated based on the above distribution)
const { result: kandelPromise } = await kandelStrategies.seeder.sow(seed);
const kandelInstance = await kandelPromise;
// Approve Kandel instance to use our funds
const approvalTxs = await kandelInstance.approveIfHigher();
// Wait for approval transactions (one for base, one for quote) to be mined
const approvalReceipts = await Promise.all(approvalTxs.map((x) => x?.wait()));
// To mint test tokens the following can be used
await (
await market.base.contract.mint(
market.base.toUnits(offeredVolumes.requiredBase),
)
).wait();
await (
await market.quote.contract.mint(
market.quote.toUnits(offeredVolumes.requiredQuote),
)
).wait();
// Populate the Kandel instance according to our desired distribution (can be multiple transactions if there are many price points)
const populateTxs = await kandelInstance.populateGeometricDistribution({
distribution: finalDistribution,
depositBaseAmount: offeredVolumes.requiredBase,
depositQuoteAmount: offeredVolumes.requiredQuote,
});
// The populate uses the recommended provision of native tokens for the offers which can be inspected with:
ethers.utils.formatUnits(populateTxs[0].value, "ether");
// The recommended provision was calculated using this:
await kandelStrategies.seeder.getRequiredProvision(seed, finalDistribution);
// Wait for the populate transactions to be mined
const populateReceipts = await Promise.all(populateTxs.map((x) => x.wait()));
// If the transactions went through, then the kandel is now populated and has the funds transferred to it
console.log(
"Kandel balance of base =",
await kandelInstance.getBalance("asks"),
"and quote =",
await kandelInstance.getBalance("bids"),
);
// Retrieve deployed Kandels owned by the wallet via the farm which detects Kandels by inspecting events from the seeder.
const ownedKandels = await kandelStrategies.farm.getKandels({
owner: wallet.address,
});
// Get an instance to interact with one of the deployed Kandels
const deployedKandel = await kandelStrategies.instance({
address: ownedKandels[0].kandelAddress,
});
// We can get the status of the offers using the following which retrieves data for all the Kandel offers and correlates it with the given mid price
const offerStatuses = await deployedKandel.getOfferStatuses(1000);
// Inspect the lowest priced bid
console.log(offerStatuses.statuses[0].bids);
// Finally, we may at some point want to withdraw the entire instance and all funds
const withdrawTxs = await deployedKandel.retractAndWithdraw();
const withdrawReceipts = await Promise.all(withdrawTxs.map((x) => x.wait()));
// Check the Kandel instance balances after withdrawal are now 0
console.log(
"Kandel balance of base =",
await kandelInstance.getBalance("asks"),
"and quote =",
await kandelInstance.getBalance("bids"),
);