Skip to content

Commit

Permalink
feat: added user vaults
Browse files Browse the repository at this point in the history
  • Loading branch information
mishuagopian committed Jan 12, 2024
1 parent 889ec62 commit d371246
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { Leverage } from "./contracts/Leverage";
import { MslV4 } from "./contracts/MslV4";
import { MslV5 } from "./contracts/MslV5";
import { Seaport } from "./contracts/Seaport";
import { UserVaultV5 } from "./contracts/UserVaultV5";
import { areSameAddress } from "./utils";

export type Wallet = WalletClient<Transport, Chain, Account>;
Expand All @@ -48,6 +49,7 @@ export class Contracts {
MultiSourceLoanV5: MslV5;
AuctionLoanLiquidatorV4: AllV4;
AuctionLoanLiquidatorV5: AllV5;
UserVaultV5: UserVaultV5;
Leverage: Leverage;
Seaport: Seaport;
CryptoPunks: CryptoPunks;
Expand All @@ -60,6 +62,7 @@ export class Contracts {
this.MultiSourceLoanV5 = new MslV5({ walletClient });
this.AuctionLoanLiquidatorV4 = new AllV4({ walletClient });
this.AuctionLoanLiquidatorV5 = new AllV5({ walletClient });
this.UserVaultV5 = new UserVaultV5({ walletClient });
this.Leverage = new Leverage({
walletClient,
mslAddress: this.MultiSourceLoanV5.address,
Expand Down Expand Up @@ -93,6 +96,13 @@ export class Contracts {
throw new Error(`Invalid Contract Address ${contractAddress}`);
}

UserVault(contractAddress: Address) {
if (areSameAddress(contractAddress, this.UserVaultV5.address)) {
return this.UserVaultV5;
}
throw new Error(`Invalid Contract Address ${contractAddress}`);
}

ERC721(
nftAddress: Address
): GetContractReturnType<typeof erc721ABI, PublicClient, Wallet, Address> {
Expand Down
105 changes: 105 additions & 0 deletions src/contracts/UserVaultV5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Address } from "viem";

import { filterLogs, Wallet } from "@/blockchain";
import { getContracts } from "@/deploys";
import { userVaultABI as userVaultABIV5 } from "@/generated/blockchain/v5";

import { Contract } from "./Contract";

export class UserVaultV5 extends Contract<typeof userVaultABIV5> {
constructor({ walletClient }: { walletClient: Wallet }) {
const { UserVaultV5Address } = getContracts(walletClient.chain);

super({
walletClient,
address: UserVaultV5Address,
abi: userVaultABIV5,
});
}

async burnAndWithdraw({ vaultId, collections, tokenIds, tokens = [] }: {
vaultId: bigint;
collections: Address[];
tokenIds: bigint[];
tokens?: Address[]; // erc20 tokens
}) {
if (collections.length != tokenIds.length) {
throw new Error("collections and tokenIds must have the same length");
}
const txHash = await this.safeContractWrite.burnAndWithdraw([
vaultId,
collections,
tokenIds,
tokens
]);

return {
txHash,
waitTxInBlock: async () => {
const receipt = await this.bcClient.waitForTransactionReceipt({
hash: txHash,
});

const filter = await this.contract.createEventFilter.ERC721Withdrawn();
const events = filterLogs(receipt, filter);
if (events.length !== tokenIds.length) throw new Error("Withdrawn count mismatch");
return { events, ...receipt };
}
};
}

async createVault(nfts: { collection: Address, tokenIds: bigint[] }[]) {
const { id: vaultId } = await this.#mintVault();

const deposits = await Promise.all(
nfts.map(async ({ collection, tokenIds }) =>
this.depositERC721s({ vaultId, collection, tokenIds })
)
);

return {
txHash: deposits.map(({ txHash }) => txHash),
waitTxInBlock: async () => await Promise.all(
deposits.map(({ waitTxInBlock }) => waitTxInBlock())
),
};
}

async depositERC721s({ vaultId, collection, tokenIds }: {
vaultId: bigint;
collection: Address;
tokenIds: bigint[];
}) {
const txHash = await this.safeContractWrite.depositERC721s([
vaultId,
collection,
tokenIds,
]);

return {
txHash,
waitTxInBlock: async () => {
const receipt = await this.bcClient.waitForTransactionReceipt({
hash: txHash,
});

const filter = await this.contract.createEventFilter.ERC721Deposited();
const events = filterLogs(receipt, filter);
if (events.length === 0) throw new Error("Deposit not created");
return { ...events[0].args, ...receipt };
}
};
}

async #mintVault() {
const txHash = await this.safeContractWrite.mint(undefined);
const receipt = await this.bcClient.waitForTransactionReceipt({
hash: txHash,
});

const filter = await this.contract.createEventFilter.Transfer({});
const events = filterLogs(receipt, filter);
if (events.length === 0) throw new Error("Vault not created");
return { ...events[0].args, ...receipt };
}
}
7 changes: 7 additions & 0 deletions src/deploys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface Contracts {
MultiSourceLoanV5Address: Address;
AuctionLoanLiquidatorV4Address: Address;
AuctionLoanLiquidatorV5Address: Address;
UserVaultV5Address: Address;
LeverageAddress: Address;
SeaportAddress: Address;
CryptoPunksAddress: Address;
Expand Down Expand Up @@ -49,6 +50,9 @@ export const getContracts = (chain: Pick<Chain, "id">): Contracts => {
AuctionLoanLiquidatorV5Address:
ensureAddress(process.env.GONDI_AUCTION_LOAN_LIQUIDATOR_V5) ??
"0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
UserVaultV5Address:
ensureAddress(process.env.GONDI_USER_VAULT_V5) ??
"0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
LeverageAddress:
ensureAddress(process.env.GONDI_LEVERAGE) ??
"0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
Expand All @@ -68,6 +72,7 @@ export const getContracts = (chain: Pick<Chain, "id">): Contracts => {
AuctionLoanLiquidatorV4Address:
"0x29C73faa2f9180ea5a7B0bEC243ebc63a5B4f280",
AuctionLoanLiquidatorV5Address: "0xTODO", // TODO: deploy
UserVaultV5Address: "0xTODO", // TODO: deploy
LeverageAddress: "0xTODO", // TODO: deploy
SeaportAddress: "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC",
CryptoPunksAddress: "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb",
Expand All @@ -81,6 +86,8 @@ export const getContracts = (chain: Pick<Chain, "id">): Contracts => {
"0x237e4421C742d843Fdd96D22294D338507e17091",
AuctionLoanLiquidatorV5Address:
"0x97d34635b605c2f1630d6b4c6c5d222b8a2ca47d",
UserVaultV5Address:
"0x14a6Dcebb2Bb73aae1b199CCAadA75247b81976D",
LeverageAddress: "0x87Ce6e8124fFd68fa721FcC7f35fdA14A11E233e",
SeaportAddress: "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC",
CryptoPunksAddress: "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb",
Expand Down
28 changes: 28 additions & 0 deletions src/gondi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -918,4 +918,32 @@ export class Gondi {
},
};
}

async createUserVault({
nfts,
userVaultAddress = this.contracts.UserVaultV5.address,
}: {
nfts: Parameters<Contracts["UserVaultV5"]["createVault"]>[0];
userVaultAddress?: Address;
}) {
return this.contracts.UserVault(userVaultAddress).createVault(nfts);
}

async depositUserVaultERC721s({
userVaultAddress = this.contracts.UserVaultV5.address,
...data
}: {
userVaultAddress?: Address;
} & Parameters<Contracts["UserVaultV5"]["depositERC721s"]>[0]) {
return this.contracts.UserVault(userVaultAddress).depositERC721s(data);
}

async burnUserVaultAndWithdraw({
userVaultAddress = this.contracts.UserVaultV5.address,
...data
}: {
userVaultAddress?: Address
} & Parameters<Contracts["UserVaultV5"]["burnAndWithdraw"]>[0]) {
return this.contracts.UserVault(userVaultAddress).burnAndWithdraw(data);
}
}

0 comments on commit d371246

Please sign in to comment.