Skip to content

Commit

Permalink
feat: claim degen nfts
Browse files Browse the repository at this point in the history
  • Loading branch information
doomsower committed Jul 10, 2024
1 parent 7d26dd2 commit f7db320
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 2 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@
"prettier --write"
],
"*.{json,md}": "prettier --write"
}
},
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
}
3 changes: 3 additions & 0 deletions src/log/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { IFactory } from "di-at-home";
import { createRequire } from "module";
import type { DestinationStream, Logger as ILogger, LoggerOptions } from "pino";
import { pino } from "pino";

const require = createRequire(import.meta.url);

import { DI } from "../di.js";

@DI.Factory(DI.Logger)
Expand Down
95 changes: 95 additions & 0 deletions src/services/liquidate/LiquidationStrategyV3Partial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
iaclAbi,
iCreditConfiguratorV3Abi,
iCreditManagerV3Abi,
iDegenDistributorV3Abi,
} from "@gearbox-protocol/types/abi";
import type { Address, SimulateContractReturnType } from "viem";
import { getContract, parseEther } from "viem";
Expand All @@ -38,6 +39,7 @@ import AbstractLiquidationStrategyV3 from "./AbstractLiquidationStrategyV3.js";
import type {
ILiquidationStrategy,
MakeLiquidatableResult,
MerkleDistributorInfo,
PartialLiquidationPreview,
} from "./types.js";
import type { IPriceHelperContract, TokenPriceInfo } from "./viem-types.js";
Expand Down Expand Up @@ -519,6 +521,13 @@ export default class LiquidationStrategyV3Partial
this.logger.info(`set bot to ${bot} in tx ${receipt.transactionHash}`);
}
const cmToCa = await this.#getLiquidatorAccounts(cms);

try {
await this.#claimDegenNFTs(cmToCa, cms);
} catch (e) {
this.logger.warn(`failed to obtain degen NFTs: ${e}`);
}

for (const cm of cms) {
const { address, name } = cm;
const ca = cmToCa[address];
Expand Down Expand Up @@ -549,6 +558,92 @@ export default class LiquidationStrategyV3Partial
return Object.fromEntries(cms.map((cm, i) => [cm.address, results[i]]));
}

/**
* Claim NFT tokens as liquidator contract, so that the contract can open credit accounts in Degen NFT protected credit managers
* @param cmToCa
* @param cms
* @returns
*/
async #claimDegenNFTs(
cmToCa: Record<string, string>,
cms: CreditManagerData[],
): Promise<void> {
const account = this.partialLiquidator;

let nfts = 0;
for (const { address, name, degenNFT } of cms) {
if (cmToCa[address] === ADDRESS_0X0 && degenNFT !== ADDRESS_0X0) {
this.logger.debug(
`need degen NFT ${degenNFT} for credit manager ${name}`,
);
nfts++;
}
}
if (nfts === 0) {
return;
}

const distributor = await this.addressProvider.findService(
"DEGEN_DISTRIBUTOR",
0,
0,
);
this.logger.debug(`degen distributor: ${distributor}`);
const [distributorNFT, merkelRoot, claimed] =
await this.client.pub.multicall({
allowFailure: false,
contracts: [
{
address: distributor,
abi: iDegenDistributorV3Abi,
functionName: "degenNFT",
},
{
address: distributor,
abi: iDegenDistributorV3Abi,
functionName: "merkleRoot",
},
{
address: distributor,
abi: iDegenDistributorV3Abi,
functionName: "claimed",
args: [account],
},
],
});
const merkleRootURL = `https://dm.gearbox.finance/${this.config.network.toLowerCase()}_${merkelRoot}.json`;
this.logger.debug(
`merkle root: ${merkleRootURL}, degen distributor NFT: ${distributorNFT}, claimed: ${claimed}`,
);

const resp = await fetch(merkleRootURL);
const merkle = (await resp.json()) as MerkleDistributorInfo;
const claims = merkle.claims[account];
if (!claims) {
throw new Error(`${account} is not eligible for degen NFT claim`);
}
this.logger.debug(claims, `claims`);
if (BigInt(claims.amount) <= claimed) {
throw new Error(`already claimed`);
}

const receipt = await this.client.simulateAndWrite({
address: distributor,
abi: iDegenDistributorV3Abi,
functionName: "claim",
args: [
BigInt(claims.index), // uint256 index,
account, // address account,
BigInt(claims.amount), // uint256 totalAmount,
claims.proof, // bytes32[] calldata merkleProof
],
});
if (receipt.status === "reverted") {
throw new Error(`degenDistributor.claim reverted`);
}
this.logger.debug(`${account} claimed ${BigInt(claims.amount)} degenNFTs`);
}

async #registerCM(cm: CreditManagerData): Promise<void> {
const { address, name } = cm;
try {
Expand Down
15 changes: 14 additions & 1 deletion src/services/liquidate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {
OptimisticResultV2,
PartialLiquidationCondition,
} from "@gearbox-protocol/types/optimist";
import type { Address, Hex, SimulateContractReturnType } from "viem";
import type { Address, Hash, Hex, SimulateContractReturnType } from "viem";

import type {
CreditAccountData,
Expand Down Expand Up @@ -102,3 +102,16 @@ export interface MakeLiquidatableResult {
snapshotId?: Hex;
partialLiquidationCondition?: PartialLiquidationCondition;
}

export interface MerkleDistributorInfo {
merkleRoot: Hash;
tokenTotal: string;
claims: Record<
Address,
{
index: number;
amount: string;
proof: Hash[];
}
>;
}

0 comments on commit f7db320

Please sign in to comment.