From 7d2493b5b05d27f2fffec65d1eb096b82d4a9054 Mon Sep 17 00:00:00 2001 From: Shisui <90075884+0xShisui@users.noreply.github.com> Date: Tue, 4 Apr 2023 05:31:32 +0200 Subject: [PATCH] chore: Add balance check on maker bid (#136) --- src/LooksRare.ts | 8 +++++--- .../looksrare/createMakerBid.test.ts | 13 ++++++++++++ src/types.ts | 1 + src/utils/calls/nonces.ts | 4 ++-- src/utils/calls/orderValidator.ts | 4 ++-- src/utils/calls/strategies.ts | 4 ++-- src/utils/calls/tokens.ts | 20 ++++++++++++++----- src/utils/calls/transferManager.ts | 4 ++-- 8 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/LooksRare.ts b/src/LooksRare.ts index e021174..7203835 100644 --- a/src/LooksRare.ts +++ b/src/LooksRare.ts @@ -22,7 +22,7 @@ import { } from "./utils/calls/transferManager"; import { verifyMakerOrders } from "./utils/calls/orderValidator"; import { encodeParams, getTakerParamsTypes, getMakerParamsTypes } from "./utils/encodeOrderParams"; -import { setApprovalForAll, isApprovedForAll, allowance, approve } from "./utils/calls/tokens"; +import { setApprovalForAll, isApprovedForAll, allowance, approve, balanceOf } from "./utils/calls/tokens"; import { strategyInfo } from "./utils/calls/strategies"; import { ErrorMerkleTreeDepth, @@ -189,7 +189,7 @@ export class LooksRare { /** * Create a maker bid object ready to be signed * @param CreateMakerInput - * @returns the maker object and isCurrencyApproved + * @returns the maker object, isCurrencyApproved, and isBalanceSufficient */ public async createMakerBid({ collection, @@ -215,7 +215,8 @@ export class LooksRare { const spenderAddress = this.addresses.EXCHANGE_V2; // Use this.provider (MulticallProvider) in order to batch the calls - const [currentAllowance, userBidAskNonce] = await Promise.all([ + const [balance, currentAllowance, userBidAskNonce] = await Promise.all([ + balanceOf(this.provider, currency, signerAddress), allowance(this.provider, currency, signerAddress, spenderAddress), viewUserBidAskNonces(this.provider, this.addresses.EXCHANGE_V2, signerAddress), ]); @@ -241,6 +242,7 @@ export class LooksRare { return { maker: order, isCurrencyApproved: BigNumber.from(currentAllowance).gte(price), + isBalanceSufficient: BigNumber.from(balance).gte(price), }; } diff --git a/src/__tests__/looksrare/createMakerBid.test.ts b/src/__tests__/looksrare/createMakerBid.test.ts index ed32628..68faafc 100644 --- a/src/__tests__/looksrare/createMakerBid.test.ts +++ b/src/__tests__/looksrare/createMakerBid.test.ts @@ -61,6 +61,19 @@ describe("Create maker bid", () => { expect(isCurrencyApproved).to.be.true; }); + it("balance checks are false if balance is not sufficient", async () => { + const { isBalanceSufficient } = await lrUser1.createMakerBid({ + ...baseMakerInput, + price: utils.parseEther("100000"), + }); + expect(isBalanceSufficient).to.be.false; + }); + + it("balance checks are true if balance is sufficient", async () => { + const { isBalanceSufficient } = await lrUser1.createMakerBid(baseMakerInput); + expect(isBalanceSufficient).to.be.true; + }); + it("create a simple maker bid with default values", async () => { const output = await lrUser1.createMakerBid(baseMakerInput); const makerOrder: Maker = { diff --git a/src/types.ts b/src/types.ts index c43b311..a47aaae 100644 --- a/src/types.ts +++ b/src/types.ts @@ -99,6 +99,7 @@ export interface CreateMakerAskOutput { export interface CreateMakerBidOutput { maker: Maker; isCurrencyApproved: boolean; + isBalanceSufficient: boolean; } /** Input of the createMakerAsk function */ diff --git a/src/utils/calls/nonces.ts b/src/utils/calls/nonces.ts index f8c4dc3..c9205f4 100644 --- a/src/utils/calls/nonces.ts +++ b/src/utils/calls/nonces.ts @@ -1,4 +1,4 @@ -import { Contract, BigNumber, Overrides, providers, BigNumberish } from "ethers"; +import { Contract, BigNumber, Overrides, CallOverrides, providers, BigNumberish } from "ethers"; import { LooksRareProtocol } from "../../typechain/@looksrare/contracts-exchange-v2/contracts/LooksRareProtocol"; import abi from "../../abis/LooksRareProtocol.json"; import { Signer, ContractMethods } from "../../types"; @@ -7,7 +7,7 @@ export const viewUserBidAskNonces = async ( signerOrProvider: providers.Provider | Signer, address: string, account: string, - overrides?: Overrides + overrides?: CallOverrides ): Promise<{ bidNonce: BigNumber; askNonce: BigNumber }> => { const contract = new Contract(address, abi, signerOrProvider) as LooksRareProtocol; const nonces = await contract.userBidAskNonces(account, { ...overrides }); diff --git a/src/utils/calls/orderValidator.ts b/src/utils/calls/orderValidator.ts index eada7b9..54214bb 100644 --- a/src/utils/calls/orderValidator.ts +++ b/src/utils/calls/orderValidator.ts @@ -1,4 +1,4 @@ -import { Contract, Overrides, providers } from "ethers"; +import { Contract, CallOverrides, providers } from "ethers"; import { OrderValidatorV2A } from "../../typechain/@looksrare/contracts-exchange-v2/contracts/helpers/OrderValidatorV2A"; import abi from "../../abis/OrderValidatorV2A.json"; import { Signer, Maker, MerkleTree, OrderValidatorCode } from "../../types"; @@ -9,7 +9,7 @@ export const verifyMakerOrders = async ( makerOrders: Maker[], signatures: string[], merkleTrees: MerkleTree[], - overrides?: Overrides + overrides?: CallOverrides ): Promise => { const contract = new Contract(address, abi, signerOrProvider) as OrderValidatorV2A; const orders = await contract.checkMultipleMakerOrderValidities(makerOrders, signatures, merkleTrees, { diff --git a/src/utils/calls/strategies.ts b/src/utils/calls/strategies.ts index 50046b2..d3db027 100644 --- a/src/utils/calls/strategies.ts +++ b/src/utils/calls/strategies.ts @@ -1,4 +1,4 @@ -import { Contract, Overrides, providers } from "ethers"; +import { Contract, CallOverrides, providers } from "ethers"; import { LooksRareProtocol } from "../../typechain/@looksrare/contracts-exchange-v2/contracts/LooksRareProtocol"; import abi from "../../abis/LooksRareProtocol.json"; import { Signer, StrategyType, StrategyInfo } from "../../types"; @@ -7,7 +7,7 @@ export const strategyInfo = async ( signerOrProvider: providers.Provider | Signer, address: string, strategyId: StrategyType, - overrides?: Overrides + overrides?: CallOverrides ): Promise => { const contract = new Contract(address, abi, signerOrProvider) as LooksRareProtocol; const strategy = await contract.strategyInfo(strategyId, { ...overrides }); diff --git a/src/utils/calls/tokens.ts b/src/utils/calls/tokens.ts index 974d425..e9fadf4 100644 --- a/src/utils/calls/tokens.ts +++ b/src/utils/calls/tokens.ts @@ -1,4 +1,4 @@ -import { Contract, providers, Overrides, CallOverrides, BigNumber } from "ethers"; +import { Contract, providers, Overrides, CallOverrides, BigNumber, ContractTransaction } from "ethers"; import { ERC721 } from "../../typechain/solmate/src/tokens/ERC721.sol/ERC721"; import { ERC20 } from "../../typechain/solmate/src/tokens/ERC20"; import abiIERC721 from "../../abis/IERC721.json"; @@ -13,7 +13,7 @@ export const setApprovalForAll = ( operator: string, approved: boolean, overrides?: Overrides -) => { +): Promise => { const contract = new Contract(collection, abiIERC721, signer) as ERC721; return contract.setApprovalForAll(operator, approved, { ...overrides }); }; @@ -24,7 +24,7 @@ export const isApprovedForAll = ( account: string, operator: string, overrides?: CallOverrides -) => { +): Promise => { const contract = new Contract(collection, abiIERC721, signerOrProvider) as ERC721; return contract.isApprovedForAll(account, operator, { ...overrides }); }; @@ -37,7 +37,7 @@ export const allowance = ( account: string, operator: string, overrides?: Overrides -) => { +): Promise => { const contract = new Contract(currency, abiIERC20, signerOrProvider) as ERC20; return contract.allowance(account, operator, { ...overrides }); }; @@ -48,7 +48,17 @@ export const approve = ( operator: string, amount: BigNumber, overrides?: Overrides -) => { +): Promise => { const contract = new Contract(currency, abiIERC20, signer) as ERC20; return contract.approve(operator, amount, { ...overrides }); }; + +export const balanceOf = ( + signerOrProvider: providers.Provider | Signer, + currency: string, + account: string, + overrides?: CallOverrides +): Promise => { + const contract = new Contract(currency, abiIERC20, signerOrProvider) as ERC20; + return contract.balanceOf(account, { ...overrides }); +}; diff --git a/src/utils/calls/transferManager.ts b/src/utils/calls/transferManager.ts index ad90e3b..d17d99b 100644 --- a/src/utils/calls/transferManager.ts +++ b/src/utils/calls/transferManager.ts @@ -1,4 +1,4 @@ -import { Contract, Overrides, providers } from "ethers"; +import { Contract, Overrides, CallOverrides, providers } from "ethers"; import { TransferManager } from "../../typechain/@looksrare/contracts-exchange-v2/contracts/TransferManager"; import abi from "../../abis/TransferManager.json"; import { Signer, ContractMethods, BatchTransferItem } from "../../types"; @@ -8,7 +8,7 @@ export const hasUserApprovedOperator = async ( address: string, user: string, operator: string, - overrides?: Overrides + overrides?: CallOverrides ): Promise => { const contract = new Contract(address, abi, signerOrProvider) as TransferManager; const hasApproved = await contract.hasUserApprovedOperator(user, operator, { ...overrides });