diff --git a/src/__tests/encoders/batchCreatePodListing.test.ts b/src/__tests/encoders/batchCreatePodListing.test.ts new file mode 100644 index 000000000..e1ae7a631 --- /dev/null +++ b/src/__tests/encoders/batchCreatePodListing.test.ts @@ -0,0 +1,139 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import batchCreatePodListing, { CreatePodListingParams } from "@/encoders/batchCreatePodListing"; +import { FarmToMode } from "@/utils/types"; +import { decodeFunctionData } from "viem"; +import { describe, expect, it } from "vitest"; + +const mockAddress = "0x1234567890abcdef1234567890abcdef12345678" as const; + +interface DecodedPodListing { + lister: string; + fieldId: bigint; + index: bigint; + start: bigint; + podAmount: bigint; + pricePerPod: number; + maxHarvestableIndex: bigint; + minFillAmount: bigint; + mode: number; +} + +function decodeResult(data: `0x${string}`) { + const decoded = decodeFunctionData({ + abi: diamondABI, + data, + }); + return { + functionName: decoded.functionName, + listings: decoded.args[0] as unknown as DecodedPodListing[], + }; +} + +function createMockListing(overrides: Partial = {}): CreatePodListingParams { + return { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromBlockchain("1000000", 6), + start: TokenValue.fromBlockchain("0", 6), + podAmount: TokenValue.fromBlockchain("5000000", 6), + pricePerPod: TokenValue.fromBlockchain("500000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("100000000000", 6), + minFillAmount: TokenValue.fromBlockchain("1000000", 6), + mode: FarmToMode.EXTERNAL, + ...overrides, + }; +} + +describe("batchCreatePodListing encoder", () => { + it("encodes a single listing", () => { + const listing = createMockListing(); + const result = batchCreatePodListing([listing]); + + expect(result).toMatch(/^0x/); + expect(result.length).toBeGreaterThan(10); + + const { functionName, listings } = decodeResult(result); + + expect(functionName).toBe("batchCreatePodListing"); + expect(listings).toHaveLength(1); + + const decodedListing = listings[0]; + expect(decodedListing.lister.toLowerCase()).toBe(mockAddress.toLowerCase()); + expect(decodedListing.fieldId).toBe(0n); + expect(decodedListing.index).toBe(listing.index.toBigInt()); + expect(decodedListing.start).toBe(listing.start.toBigInt()); + expect(decodedListing.podAmount).toBe(listing.podAmount.toBigInt()); + expect(decodedListing.pricePerPod).toBe(Number(listing.pricePerPod.toBigInt())); + expect(decodedListing.maxHarvestableIndex).toBe(listing.maxHarvestableIndex.toBigInt()); + expect(decodedListing.minFillAmount).toBe(listing.minFillAmount.toBigInt()); + expect(decodedListing.mode).toBe(Number(FarmToMode.EXTERNAL)); + }); + + it("encodes multiple listings", () => { + const listings = [ + createMockListing({ index: TokenValue.fromBlockchain("1000000", 6) }), + createMockListing({ index: TokenValue.fromBlockchain("2000000", 6) }), + createMockListing({ index: TokenValue.fromBlockchain("3000000", 6) }), + ]; + + const result = batchCreatePodListing(listings); + const { listings: decoded } = decodeResult(result); + + expect(decoded).toHaveLength(3); + expect(decoded[0].index).toBe(listings[0].index.toBigInt()); + expect(decoded[1].index).toBe(listings[1].index.toBigInt()); + expect(decoded[2].index).toBe(listings[2].index.toBigInt()); + }); + + it("converts pricePerPod to number (uint24)", () => { + const listing = createMockListing({ + pricePerPod: TokenValue.fromBlockchain("800000", 6), + }); + + const result = batchCreatePodListing([listing]); + const { listings } = decodeResult(result); + + expect(typeof listings[0].pricePerPod).toBe("number"); + expect(listings[0].pricePerPod).toBe(800000); + }); + + it("handles FarmToMode.INTERNAL", () => { + const listing = createMockListing({ mode: FarmToMode.INTERNAL }); + + const result = batchCreatePodListing([listing]); + const { listings } = decodeResult(result); + + expect(listings[0].mode).toBe(Number(FarmToMode.INTERNAL)); + }); + + it("converts TokenValue fields to BigInt", () => { + const listing = createMockListing({ + index: TokenValue.fromHuman("100", 6), + start: TokenValue.fromHuman("10", 6), + podAmount: TokenValue.fromHuman("50", 6), + maxHarvestableIndex: TokenValue.fromHuman("999999", 6), + minFillAmount: TokenValue.fromHuman("1", 6), + }); + + const result = batchCreatePodListing([listing]); + const { listings } = decodeResult(result); + + const d = listings[0]; + expect(d.index).toBe(100000000n); + expect(d.start).toBe(10000000n); + expect(d.podAmount).toBe(50000000n); + expect(d.maxHarvestableIndex).toBe(999999000000n); + expect(d.minFillAmount).toBe(1000000n); + }); + + it("preserves lister address", () => { + const customAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as const; + const listing = createMockListing({ lister: customAddress }); + + const result = batchCreatePodListing([listing]); + const { listings } = decodeResult(result); + + expect(listings[0].lister.toLowerCase()).toBe(customAddress.toLowerCase()); + }); +}); diff --git a/src/__tests/encoders/batchFillPodListing.test.ts b/src/__tests/encoders/batchFillPodListing.test.ts new file mode 100644 index 000000000..417964b34 --- /dev/null +++ b/src/__tests/encoders/batchFillPodListing.test.ts @@ -0,0 +1,225 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import batchFillPodListing, { FillPodListingParams } from "@/encoders/batchFillPodListing"; +import { FarmFromMode, FarmToMode } from "@/utils/types"; +import { decodeFunctionData } from "viem"; +import { describe, expect, it } from "vitest"; + +const mockAddress = "0x1234567890abcdef1234567890abcdef12345678" as const; + +interface DecodedFillParams { + podListing: { + lister: string; + fieldId: bigint; + index: bigint; + start: bigint; + podAmount: bigint; + pricePerPod: number; + maxHarvestableIndex: bigint; + minFillAmount: bigint; + mode: number; + }; + beanAmount: bigint; + mode: number; +} + +function decodeResult(data: `0x${string}`) { + const decoded = decodeFunctionData({ + abi: diamondABI, + data, + }); + return { + functionName: decoded.functionName, + params: decoded.args[0] as unknown as DecodedFillParams[], + }; +} + +function createMockFillParams(overrides: Partial = {}): FillPodListingParams { + return { + podListing: { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromBlockchain("1000000", 6), + start: TokenValue.fromBlockchain("0", 6), + podAmount: TokenValue.fromBlockchain("5000000", 6), + pricePerPod: TokenValue.fromBlockchain("500000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("100000000000", 6), + minFillAmount: TokenValue.fromBlockchain("1000000", 6), + mode: FarmToMode.EXTERNAL, + ...overrides?.podListing, + }, + beanAmount: TokenValue.fromBlockchain("2000000", 6), + mode: FarmFromMode.EXTERNAL, + ...("beanAmount" in overrides ? { beanAmount: overrides.beanAmount } : {}), + ...("mode" in overrides && overrides.mode !== undefined ? { mode: overrides.mode } : {}), + }; +} + +describe("batchFillPodListing encoder", () => { + it("encodes a single fill", () => { + const fill = createMockFillParams(); + const result = batchFillPodListing([fill]); + + expect(result).toMatch(/^0x/); + expect(result.length).toBeGreaterThan(10); + + const { functionName, params } = decodeResult(result); + + expect(functionName).toBe("batchFillPodListing"); + expect(params).toHaveLength(1); + + const decoded = params[0]; + expect(decoded.podListing.lister.toLowerCase()).toBe(mockAddress.toLowerCase()); + expect(decoded.podListing.fieldId).toBe(0n); + expect(decoded.podListing.index).toBe(fill.podListing.index.toBigInt()); + expect(decoded.podListing.start).toBe(fill.podListing.start.toBigInt()); + expect(decoded.podListing.podAmount).toBe(fill.podListing.podAmount.toBigInt()); + expect(decoded.podListing.pricePerPod).toBe(Number(fill.podListing.pricePerPod.toBigInt())); + expect(decoded.podListing.maxHarvestableIndex).toBe(fill.podListing.maxHarvestableIndex.toBigInt()); + expect(decoded.podListing.minFillAmount).toBe(fill.podListing.minFillAmount.toBigInt()); + expect(decoded.podListing.mode).toBe(Number(FarmToMode.EXTERNAL)); + expect(decoded.beanAmount).toBe(fill.beanAmount.toBigInt()); + expect(decoded.mode).toBe(Number(FarmFromMode.EXTERNAL)); + }); + + it("encodes multiple fills", () => { + const fills: FillPodListingParams[] = [ + createMockFillParams(), + createMockFillParams({ + podListing: { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromBlockchain("2000000", 6), + start: TokenValue.fromBlockchain("0", 6), + podAmount: TokenValue.fromBlockchain("3000000", 6), + pricePerPod: TokenValue.fromBlockchain("600000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("100000000000", 6), + minFillAmount: TokenValue.fromBlockchain("500000", 6), + mode: FarmToMode.EXTERNAL, + }, + beanAmount: TokenValue.fromBlockchain("1500000", 6), + mode: FarmFromMode.INTERNAL, + }), + createMockFillParams({ + podListing: { + lister: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as const, + fieldId: 0n, + index: TokenValue.fromBlockchain("3000000", 6), + start: TokenValue.fromBlockchain("100000", 6), + podAmount: TokenValue.fromBlockchain("8000000", 6), + pricePerPod: TokenValue.fromBlockchain("450000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("200000000000", 6), + minFillAmount: TokenValue.fromBlockchain("2000000", 6), + mode: FarmToMode.INTERNAL, + }, + beanAmount: TokenValue.fromBlockchain("4000000", 6), + mode: FarmFromMode.EXTERNAL, + }), + ]; + + const result = batchFillPodListing(fills); + const { params } = decodeResult(result); + + expect(params).toHaveLength(3); + expect(params[0].podListing.index).toBe(fills[0].podListing.index.toBigInt()); + expect(params[1].podListing.index).toBe(fills[1].podListing.index.toBigInt()); + expect(params[2].podListing.index).toBe(fills[2].podListing.index.toBigInt()); + expect(params[1].beanAmount).toBe(fills[1].beanAmount.toBigInt()); + expect(params[2].podListing.lister.toLowerCase()).toBe("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"); + }); + + it("converts pricePerPod to number (uint24)", () => { + const fill = createMockFillParams({ + podListing: { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromBlockchain("1000000", 6), + start: TokenValue.fromBlockchain("0", 6), + podAmount: TokenValue.fromBlockchain("5000000", 6), + pricePerPod: TokenValue.fromBlockchain("800000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("100000000000", 6), + minFillAmount: TokenValue.fromBlockchain("1000000", 6), + mode: FarmToMode.EXTERNAL, + }, + }); + + const result = batchFillPodListing([fill]); + const { params } = decodeResult(result); + + expect(typeof params[0].podListing.pricePerPod).toBe("number"); + expect(params[0].podListing.pricePerPod).toBe(800000); + }); + + it("handles FarmFromMode.INTERNAL", () => { + const fill = createMockFillParams({ + podListing: { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromBlockchain("1000000", 6), + start: TokenValue.fromBlockchain("0", 6), + podAmount: TokenValue.fromBlockchain("5000000", 6), + pricePerPod: TokenValue.fromBlockchain("500000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("100000000000", 6), + minFillAmount: TokenValue.fromBlockchain("1000000", 6), + mode: FarmToMode.EXTERNAL, + }, + beanAmount: TokenValue.fromBlockchain("2000000", 6), + mode: FarmFromMode.INTERNAL, + }); + + const result = batchFillPodListing([fill]); + const { params } = decodeResult(result); + + expect(params[0].mode).toBe(Number(FarmFromMode.INTERNAL)); + }); + + it("handles FarmToMode on podListing.mode", () => { + const fill = createMockFillParams({ + podListing: { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromBlockchain("1000000", 6), + start: TokenValue.fromBlockchain("0", 6), + podAmount: TokenValue.fromBlockchain("5000000", 6), + pricePerPod: TokenValue.fromBlockchain("500000", 6), + maxHarvestableIndex: TokenValue.fromBlockchain("100000000000", 6), + minFillAmount: TokenValue.fromBlockchain("1000000", 6), + mode: FarmToMode.INTERNAL, + }, + }); + + const result = batchFillPodListing([fill]); + const { params } = decodeResult(result); + + expect(params[0].podListing.mode).toBe(Number(FarmToMode.INTERNAL)); + }); + + it("converts TokenValue fields to BigInt correctly", () => { + const fill = createMockFillParams({ + podListing: { + lister: mockAddress, + fieldId: 0n, + index: TokenValue.fromHuman("100", 6), + start: TokenValue.fromHuman("10", 6), + podAmount: TokenValue.fromHuman("50", 6), + pricePerPod: TokenValue.fromBlockchain("500000", 6), + maxHarvestableIndex: TokenValue.fromHuman("999999", 6), + minFillAmount: TokenValue.fromHuman("1", 6), + mode: FarmToMode.EXTERNAL, + }, + beanAmount: TokenValue.fromHuman("25", 6), + mode: FarmFromMode.EXTERNAL, + }); + + const result = batchFillPodListing([fill]); + const { params } = decodeResult(result); + + const d = params[0]; + expect(d.podListing.index).toBe(100000000n); + expect(d.podListing.start).toBe(10000000n); + expect(d.podListing.podAmount).toBe(50000000n); + expect(d.podListing.maxHarvestableIndex).toBe(999999000000n); + expect(d.podListing.minFillAmount).toBe(1000000n); + expect(d.beanAmount).toBe(25000000n); + }); +}); diff --git a/src/components/CombineSelect.tsx b/src/components/CombineSelect.tsx index a3bedf2e6..0771655b4 100644 --- a/src/components/CombineSelect.tsx +++ b/src/components/CombineSelect.tsx @@ -63,13 +63,19 @@ export default function CombineSelect({ setTransferData, token, disabled }: Comb setSubmitting(true); toast.loading("Combining deposits..."); - const encodedCalls = encodeGroupCombineCalls(validGroups, token, farmerDeposits.deposits); + const encodedCall = encodeGroupCombineCalls(validGroups, token, farmerDeposits.deposits); + + if (!encodedCall) { + toast.error("No deposits to combine"); + setSubmitting(false); + return; + } await writeWithEstimateGas({ address: protocolAddress, abi: diamondABI, functionName: "farm", - args: [encodedCalls], + args: [[encodedCall]], }); setOpen(false); diff --git a/src/constants/abi/diamondABI.ts b/src/constants/abi/diamondABI.ts index dc0414c6e..27d93216d 100644 --- a/src/constants/abi/diamondABI.ts +++ b/src/constants/abi/diamondABI.ts @@ -10933,4 +10933,408 @@ export const diamondABI = [ stateMutability: "nonpayable", type: "function", }, + { + inputs: [ + { + components: [ + { + internalType: "uint256", + name: "fieldId", + type: "uint256", + }, + { + internalType: "uint256", + name: "index", + type: "uint256", + }, + ], + internalType: "struct CancelPodListingParams[]", + name: "params", + type: "tuple[]", + }, + ], + name: "batchCancelPodListing", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "orderer", + type: "address", + }, + { + internalType: "uint256", + name: "fieldId", + type: "uint256", + }, + { + internalType: "uint24", + name: "pricePerPod", + type: "uint24", + }, + { + internalType: "uint256", + name: "maxPlaceInLine", + type: "uint256", + }, + { + internalType: "uint256", + name: "minFillAmount", + type: "uint256", + }, + ], + internalType: "struct Order.PodOrder[]", + name: "podOrders", + type: "tuple[]", + }, + { + internalType: "enum LibTransfer.To", + name: "mode", + type: "uint8", + }, + ], + name: "batchCancelPodOrder", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "lister", + type: "address", + }, + { + internalType: "uint256", + name: "fieldId", + type: "uint256", + }, + { + internalType: "uint256", + name: "index", + type: "uint256", + }, + { + internalType: "uint256", + name: "start", + type: "uint256", + }, + { + internalType: "uint256", + name: "podAmount", + type: "uint256", + }, + { + internalType: "uint24", + name: "pricePerPod", + type: "uint24", + }, + { + internalType: "uint256", + name: "maxHarvestableIndex", + type: "uint256", + }, + { + internalType: "uint256", + name: "minFillAmount", + type: "uint256", + }, + { + internalType: "enum LibTransfer.To", + name: "mode", + type: "uint8", + }, + ], + internalType: "struct Listing.PodListing[]", + name: "podListings", + type: "tuple[]", + }, + ], + name: "batchCreatePodListing", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: "address", + name: "lister", + type: "address", + }, + { + internalType: "uint256", + name: "fieldId", + type: "uint256", + }, + { + internalType: "uint256", + name: "index", + type: "uint256", + }, + { + internalType: "uint256", + name: "start", + type: "uint256", + }, + { + internalType: "uint256", + name: "podAmount", + type: "uint256", + }, + { + internalType: "uint24", + name: "pricePerPod", + type: "uint24", + }, + { + internalType: "uint256", + name: "maxHarvestableIndex", + type: "uint256", + }, + { + internalType: "uint256", + name: "minFillAmount", + type: "uint256", + }, + { + internalType: "enum LibTransfer.To", + name: "mode", + type: "uint8", + }, + ], + internalType: "struct Listing.PodListing", + name: "podListing", + type: "tuple", + }, + { + internalType: "uint256", + name: "beanAmount", + type: "uint256", + }, + { + internalType: "enum LibTransfer.From", + name: "mode", + type: "uint8", + }, + ], + internalType: "struct FillPodListingParams[]", + name: "params", + type: "tuple[]", + }, + ], + name: "batchFillPodListing", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: "address", + name: "orderer", + type: "address", + }, + { + internalType: "uint256", + name: "fieldId", + type: "uint256", + }, + { + internalType: "uint24", + name: "pricePerPod", + type: "uint24", + }, + { + internalType: "uint256", + name: "maxPlaceInLine", + type: "uint256", + }, + { + internalType: "uint256", + name: "minFillAmount", + type: "uint256", + }, + ], + internalType: "struct Order.PodOrder", + name: "podOrder", + type: "tuple", + }, + { + internalType: "uint256", + name: "beanAmount", + type: "uint256", + }, + { + internalType: "enum LibTransfer.From", + name: "mode", + type: "uint8", + }, + ], + internalType: "struct CreatePodOrderParams[]", + name: "params", + type: "tuple[]", + }, + ], + name: "batchCreatePodOrder", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: "address", + name: "orderer", + type: "address", + }, + { + internalType: "uint256", + name: "fieldId", + type: "uint256", + }, + { + internalType: "uint24", + name: "pricePerPod", + type: "uint24", + }, + { + internalType: "uint256", + name: "maxPlaceInLine", + type: "uint256", + }, + { + internalType: "uint256", + name: "minFillAmount", + type: "uint256", + }, + ], + internalType: "struct Order.PodOrder", + name: "podOrder", + type: "tuple", + }, + { + internalType: "uint256", + name: "index", + type: "uint256", + }, + { + internalType: "uint256", + name: "start", + type: "uint256", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + internalType: "enum LibTransfer.To", + name: "mode", + type: "uint8", + }, + ], + internalType: "struct FillPodOrderParams[]", + name: "params", + type: "tuple[]", + }, + ], + name: "batchFillPodOrder", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "bytes", + name: "convertData", + type: "bytes", + }, + { + internalType: "int96[]", + name: "stems", + type: "int96[]", + }, + { + internalType: "uint256[]", + name: "amounts", + type: "uint256[]", + }, + { + internalType: "int256", + name: "grownStalkSlippage", + type: "int256", + }, + ], + internalType: "struct ConvertBatchFacet.ConvertParams[]", + name: "converts", + type: "tuple[]", + }, + ], + name: "batchConvert", + outputs: [ + { + components: [ + { + internalType: "uint8", + name: "convertKind", + type: "uint8", + }, + { + internalType: "int96", + name: "toStem", + type: "int96", + }, + { + internalType: "uint256", + name: "fromAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "toAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "fromBdv", + type: "uint256", + }, + { + internalType: "uint256", + name: "toBdv", + type: "uint256", + }, + ], + internalType: "struct ConvertBatchFacet.ConvertOutput[]", + name: "convertOutputs", + type: "tuple[]", + }, + ], + stateMutability: "payable", + type: "function", + }, ] as const; diff --git a/src/encoders/batchCancelPodListing.ts b/src/encoders/batchCancelPodListing.ts new file mode 100644 index 000000000..345dc6ad3 --- /dev/null +++ b/src/encoders/batchCancelPodListing.ts @@ -0,0 +1,26 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import { encodeFunctionData } from "viem"; + +export interface CancelPodListingParams { + fieldId: bigint; + index: TokenValue; +} + +/** + * Encodes a batch cancel pod listing transaction + * @param params Array of listing parameters to cancel + * @returns Encoded function data for batchCancelPodListing + */ +export default function batchCancelPodListing(params: CancelPodListingParams[]): `0x${string}` { + const args = params.map((p) => ({ + fieldId: p.fieldId, + index: p.index.toBigInt(), + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchCancelPodListing", + args: [args], + }); +} diff --git a/src/encoders/batchCancelPodOrder.ts b/src/encoders/batchCancelPodOrder.ts new file mode 100644 index 000000000..f76d5280d --- /dev/null +++ b/src/encoders/batchCancelPodOrder.ts @@ -0,0 +1,34 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import { FarmToMode } from "@/utils/types"; +import { Address, encodeFunctionData } from "viem"; + +export interface CancelPodOrderParams { + orderer: Address; + fieldId: bigint; + pricePerPod: TokenValue; + maxPlaceInLine: TokenValue; + minFillAmount: TokenValue; +} + +/** + * Encodes a batch cancel pod order transaction + * @param orders Array of order parameters to cancel + * @param mode The destination mode for returned tokens (INTERNAL or EXTERNAL) + * @returns Encoded function data for batchCancelPodOrder + */ +export default function batchCancelPodOrder(orders: CancelPodOrderParams[], mode: FarmToMode): `0x${string}` { + const args = orders.map((o) => ({ + orderer: o.orderer, + fieldId: o.fieldId, + pricePerPod: o.pricePerPod.toNumber(), // uint24 expects number, not bigint + maxPlaceInLine: o.maxPlaceInLine.toBigInt(), + minFillAmount: o.minFillAmount.toBigInt(), + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchCancelPodOrder", + args: [args, Number(mode)], + }); +} diff --git a/src/encoders/batchConvert.ts b/src/encoders/batchConvert.ts new file mode 100644 index 000000000..bff84a791 --- /dev/null +++ b/src/encoders/batchConvert.ts @@ -0,0 +1,39 @@ +import { diamondABI } from "@/constants/abi/diamondABI"; +import { HashString } from "@/utils/types.generic"; +import { encodeFunctionData } from "viem"; + +/** + * Parameters for a single convert operation within a batch. + * Each entry represents one deposit group to combine via same-token convert. + */ +export interface BatchConvertParams { + /** Encoded conversion parameters (from calculateConvertData) */ + convertData: HashString; + /** Deposit stems to convert (int96[]) */ + stems: bigint[]; + /** Amounts per deposit to convert (uint256[]) */ + amounts: bigint[]; + /** Grown stalk slippage tolerance (int256). Use 0n for same-token combines. */ + grownStalkSlippage: bigint; +} + +/** + * Encodes a batch convert transaction that combines multiple convert operations + * into a single on-chain call. Used for deposit combine/sort optimization. + * @param params Array of convert parameters (one per deposit group) + * @returns Encoded function data for batchConvert + */ +export default function batchConvert(params: BatchConvertParams[]): `0x${string}` { + const args = params.map((p) => ({ + convertData: p.convertData, + stems: p.stems, + amounts: p.amounts, + grownStalkSlippage: p.grownStalkSlippage, + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchConvert", + args: [args], + }); +} diff --git a/src/encoders/batchCreatePodListing.ts b/src/encoders/batchCreatePodListing.ts new file mode 100644 index 000000000..4b67266aa --- /dev/null +++ b/src/encoders/batchCreatePodListing.ts @@ -0,0 +1,41 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import { FarmToMode } from "@/utils/types"; +import { Address, encodeFunctionData } from "viem"; + +export interface CreatePodListingParams { + lister: Address; + fieldId: bigint; + index: TokenValue; + start: TokenValue; + podAmount: TokenValue; + pricePerPod: TokenValue; + maxHarvestableIndex: TokenValue; + minFillAmount: TokenValue; + mode: FarmToMode; +} + +/** + * Encodes a batch create pod listing transaction + * @param listings Array of listing parameters to create + * @returns Encoded function data for batchCreatePodListing + */ +export default function batchCreatePodListing(listings: CreatePodListingParams[]): `0x${string}` { + const args = listings.map((l) => ({ + lister: l.lister, + fieldId: l.fieldId, + index: l.index.toBigInt(), + start: l.start.toBigInt(), + podAmount: l.podAmount.toBigInt(), + pricePerPod: Number(l.pricePerPod.toBigInt()), // uint24 expects number + maxHarvestableIndex: l.maxHarvestableIndex.toBigInt(), + minFillAmount: l.minFillAmount.toBigInt(), + mode: Number(l.mode), + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchCreatePodListing", + args: [args], + }); +} diff --git a/src/encoders/batchCreatePodOrder.ts b/src/encoders/batchCreatePodOrder.ts new file mode 100644 index 000000000..f3159dc79 --- /dev/null +++ b/src/encoders/batchCreatePodOrder.ts @@ -0,0 +1,39 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import { FarmFromMode } from "@/utils/types"; +import { Address, encodeFunctionData } from "viem"; + +export interface CreatePodOrderParams { + orderer: Address; + fieldId: bigint; + pricePerPod: TokenValue; + maxPlaceInLine: TokenValue; + minFillAmount: TokenValue; + beanAmount: TokenValue; + mode: FarmFromMode; +} + +/** + * Encodes a batch create pod order transaction + * @param orders Array of order parameters to create + * @returns Encoded function data for batchCreatePodOrder + */ +export default function batchCreatePodOrder(orders: CreatePodOrderParams[]): `0x${string}` { + const args = orders.map((o) => ({ + podOrder: { + orderer: o.orderer, + fieldId: o.fieldId, + pricePerPod: Number(o.pricePerPod.toBigInt()), // uint24 expects number + maxPlaceInLine: o.maxPlaceInLine.toBigInt(), + minFillAmount: o.minFillAmount.toBigInt(), + }, + beanAmount: o.beanAmount.toBigInt(), + mode: Number(o.mode), + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchCreatePodOrder", + args: [args], + }); +} diff --git a/src/encoders/batchFillPodListing.ts b/src/encoders/batchFillPodListing.ts new file mode 100644 index 000000000..949678c3f --- /dev/null +++ b/src/encoders/batchFillPodListing.ts @@ -0,0 +1,49 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import { FarmFromMode, FarmToMode } from "@/utils/types"; +import { Address, encodeFunctionData } from "viem"; + +export interface FillPodListingParams { + podListing: { + lister: Address; + fieldId: bigint; + index: TokenValue; + start: TokenValue; + podAmount: TokenValue; + pricePerPod: TokenValue; + maxHarvestableIndex: TokenValue; + minFillAmount: TokenValue; + mode: FarmToMode; + }; + beanAmount: TokenValue; + mode: FarmFromMode; +} + +/** + * Encodes a batch fill pod listing transaction + * @param params Array of fill listing parameters + * @returns Encoded function data for batchFillPodListing + */ +export default function batchFillPodListing(params: FillPodListingParams[]): `0x${string}` { + const args = params.map((p) => ({ + podListing: { + lister: p.podListing.lister, + fieldId: p.podListing.fieldId, + index: p.podListing.index.toBigInt(), + start: p.podListing.start.toBigInt(), + podAmount: p.podListing.podAmount.toBigInt(), + pricePerPod: Number(p.podListing.pricePerPod.toBigInt()), // uint24 + maxHarvestableIndex: p.podListing.maxHarvestableIndex.toBigInt(), + minFillAmount: p.podListing.minFillAmount.toBigInt(), + mode: Number(p.podListing.mode), + }, + beanAmount: p.beanAmount.toBigInt(), + mode: Number(p.mode), + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchFillPodListing", + args: [args], + }); +} diff --git a/src/encoders/batchFillPodOrder.ts b/src/encoders/batchFillPodOrder.ts new file mode 100644 index 000000000..a24c9aa97 --- /dev/null +++ b/src/encoders/batchFillPodOrder.ts @@ -0,0 +1,45 @@ +import { TokenValue } from "@/classes/TokenValue"; +import { diamondABI } from "@/constants/abi/diamondABI"; +import { FarmToMode } from "@/utils/types"; +import { Address, encodeFunctionData } from "viem"; + +export interface FillPodOrderParams { + podOrder: { + orderer: Address; + fieldId: bigint; + pricePerPod: TokenValue; + maxPlaceInLine: TokenValue; + minFillAmount: TokenValue; + }; + index: TokenValue; + start: TokenValue; + amount: TokenValue; + mode: FarmToMode; +} + +/** + * Encodes a batch fill pod order transaction + * @param params Array of fill order parameters + * @returns Encoded function data for batchFillPodOrder + */ +export default function batchFillPodOrder(params: FillPodOrderParams[]): `0x${string}` { + const args = params.map((p) => ({ + podOrder: { + orderer: p.podOrder.orderer, + fieldId: p.podOrder.fieldId, + pricePerPod: Number(p.podOrder.pricePerPod.toBigInt()), // uint24 + maxPlaceInLine: p.podOrder.maxPlaceInLine.toBigInt(), + minFillAmount: p.podOrder.minFillAmount.toBigInt(), + }, + index: p.index.toBigInt(), + start: p.start.toBigInt(), + amount: p.amount.toBigInt(), + mode: Number(p.mode), + })); + + return encodeFunctionData({ + abi: diamondABI, + functionName: "batchFillPodOrder", + args: [args], + }); +} diff --git a/src/encoders/index.ts b/src/encoders/index.ts index 8cc3ec41c..c5b22a673 100644 --- a/src/encoders/index.ts +++ b/src/encoders/index.ts @@ -1,4 +1,11 @@ import advancedPipe from "./advancedPipe"; +import batchCancelPodListing from "./batchCancelPodListing"; +import batchCancelPodOrder from "./batchCancelPodOrder"; +import batchConvert from "./batchConvert"; +import batchCreatePodListing from "./batchCreatePodListing"; +import batchCreatePodOrder from "./batchCreatePodOrder"; +import batchFillPodListing from "./batchFillPodListing"; +import batchFillPodOrder from "./batchFillPodOrder"; import erc20Approve from "./erc20Approve"; import erc20BalanceOf from "./erc20BalanceOf"; import erc20Transfer from "./erc20Transfer"; @@ -34,6 +41,16 @@ import wrapEth from "./wrapEth"; const encoders = { advancedPipe, + // marketplace batch operations + market: { + batchCancelPodListing, + batchCancelPodOrder, + batchCreatePodListing, + batchCreatePodOrder, + batchFillPodListing, + batchFillPodOrder, + }, + // junction junction: { check: junctionCheck, @@ -47,6 +64,7 @@ const encoders = { silo: { pipelineConvert, convert, + batchConvert, withdraw: siloWithdraw, getMaxAmountIn, getAmountOut, diff --git a/src/generated/contractHooks.ts b/src/generated/contractHooks.ts index 26efd6000..7b7ce9be3 100644 --- a/src/generated/contractHooks.ts +++ b/src/generated/contractHooks.ts @@ -6214,6 +6214,238 @@ export const beanstalkAbi = [ ], stateMutability: 'nonpayable', }, + { + type: 'function', + inputs: [ + { + name: 'params', + internalType: 'struct CancelPodListingParams[]', + type: 'tuple[]', + components: [ + { name: 'fieldId', internalType: 'uint256', type: 'uint256' }, + { name: 'index', internalType: 'uint256', type: 'uint256' }, + ], + }, + ], + name: 'batchCancelPodListing', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [ + { + name: 'podOrders', + internalType: 'struct Order.PodOrder[]', + type: 'tuple[]', + components: [ + { name: 'orderer', internalType: 'address', type: 'address' }, + { name: 'fieldId', internalType: 'uint256', type: 'uint256' }, + { name: 'pricePerPod', internalType: 'uint24', type: 'uint24' }, + { name: 'maxPlaceInLine', internalType: 'uint256', type: 'uint256' }, + { name: 'minFillAmount', internalType: 'uint256', type: 'uint256' }, + ], + }, + { name: 'mode', internalType: 'enum LibTransfer.To', type: 'uint8' }, + ], + name: 'batchCancelPodOrder', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [ + { + name: 'podListings', + internalType: 'struct Listing.PodListing[]', + type: 'tuple[]', + components: [ + { name: 'lister', internalType: 'address', type: 'address' }, + { name: 'fieldId', internalType: 'uint256', type: 'uint256' }, + { name: 'index', internalType: 'uint256', type: 'uint256' }, + { name: 'start', internalType: 'uint256', type: 'uint256' }, + { name: 'podAmount', internalType: 'uint256', type: 'uint256' }, + { name: 'pricePerPod', internalType: 'uint24', type: 'uint24' }, + { + name: 'maxHarvestableIndex', + internalType: 'uint256', + type: 'uint256', + }, + { name: 'minFillAmount', internalType: 'uint256', type: 'uint256' }, + { name: 'mode', internalType: 'enum LibTransfer.To', type: 'uint8' }, + ], + }, + ], + name: 'batchCreatePodListing', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [ + { + name: 'params', + internalType: 'struct FillPodListingParams[]', + type: 'tuple[]', + components: [ + { + name: 'podListing', + internalType: 'struct Listing.PodListing', + type: 'tuple', + components: [ + { name: 'lister', internalType: 'address', type: 'address' }, + { name: 'fieldId', internalType: 'uint256', type: 'uint256' }, + { name: 'index', internalType: 'uint256', type: 'uint256' }, + { name: 'start', internalType: 'uint256', type: 'uint256' }, + { name: 'podAmount', internalType: 'uint256', type: 'uint256' }, + { name: 'pricePerPod', internalType: 'uint24', type: 'uint24' }, + { + name: 'maxHarvestableIndex', + internalType: 'uint256', + type: 'uint256', + }, + { + name: 'minFillAmount', + internalType: 'uint256', + type: 'uint256', + }, + { + name: 'mode', + internalType: 'enum LibTransfer.To', + type: 'uint8', + }, + ], + }, + { name: 'beanAmount', internalType: 'uint256', type: 'uint256' }, + { + name: 'mode', + internalType: 'enum LibTransfer.From', + type: 'uint8', + }, + ], + }, + ], + name: 'batchFillPodListing', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [ + { + name: 'params', + internalType: 'struct CreatePodOrderParams[]', + type: 'tuple[]', + components: [ + { + name: 'podOrder', + internalType: 'struct Order.PodOrder', + type: 'tuple', + components: [ + { name: 'orderer', internalType: 'address', type: 'address' }, + { name: 'fieldId', internalType: 'uint256', type: 'uint256' }, + { name: 'pricePerPod', internalType: 'uint24', type: 'uint24' }, + { + name: 'maxPlaceInLine', + internalType: 'uint256', + type: 'uint256', + }, + { + name: 'minFillAmount', + internalType: 'uint256', + type: 'uint256', + }, + ], + }, + { name: 'beanAmount', internalType: 'uint256', type: 'uint256' }, + { + name: 'mode', + internalType: 'enum LibTransfer.From', + type: 'uint8', + }, + ], + }, + ], + name: 'batchCreatePodOrder', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [ + { + name: 'params', + internalType: 'struct FillPodOrderParams[]', + type: 'tuple[]', + components: [ + { + name: 'podOrder', + internalType: 'struct Order.PodOrder', + type: 'tuple', + components: [ + { name: 'orderer', internalType: 'address', type: 'address' }, + { name: 'fieldId', internalType: 'uint256', type: 'uint256' }, + { name: 'pricePerPod', internalType: 'uint24', type: 'uint24' }, + { + name: 'maxPlaceInLine', + internalType: 'uint256', + type: 'uint256', + }, + { + name: 'minFillAmount', + internalType: 'uint256', + type: 'uint256', + }, + ], + }, + { name: 'index', internalType: 'uint256', type: 'uint256' }, + { name: 'start', internalType: 'uint256', type: 'uint256' }, + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + { name: 'mode', internalType: 'enum LibTransfer.To', type: 'uint8' }, + ], + }, + ], + name: 'batchFillPodOrder', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [ + { + name: 'converts', + internalType: 'struct ConvertBatchFacet.ConvertParams[]', + type: 'tuple[]', + components: [ + { name: 'convertData', internalType: 'bytes', type: 'bytes' }, + { name: 'stems', internalType: 'int96[]', type: 'int96[]' }, + { name: 'amounts', internalType: 'uint256[]', type: 'uint256[]' }, + { + name: 'grownStalkSlippage', + internalType: 'int256', + type: 'int256', + }, + ], + }, + ], + name: 'batchConvert', + outputs: [ + { + name: 'convertOutputs', + internalType: 'struct ConvertBatchFacet.ConvertOutput[]', + type: 'tuple[]', + components: [ + { name: 'convertKind', internalType: 'uint8', type: 'uint8' }, + { name: 'toStem', internalType: 'int96', type: 'int96' }, + { name: 'fromAmount', internalType: 'uint256', type: 'uint256' }, + { name: 'toAmount', internalType: 'uint256', type: 'uint256' }, + { name: 'fromBdv', internalType: 'uint256', type: 'uint256' }, + { name: 'toBdv', internalType: 'uint256', type: 'uint256' }, + ], + }, + ], + stateMutability: 'payable', + }, ] as const /** @@ -14637,6 +14869,118 @@ export const useWriteBeanstalk_SowWithReferral = functionName: 'sowWithReferral', }) +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCancelPodListing"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchCancelPodListing = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCancelPodListing', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCancelPodOrder"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchCancelPodOrder = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCancelPodOrder', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCreatePodListing"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchCreatePodListing = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCreatePodListing', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchFillPodListing"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchFillPodListing = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchFillPodListing', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCreatePodOrder"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchCreatePodOrder = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCreatePodOrder', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchFillPodOrder"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchFillPodOrder = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchFillPodOrder', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchConvert"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useWriteBeanstalk_BatchConvert = + /*#__PURE__*/ createUseWriteContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchConvert', + }) + /** * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ * @@ -15893,6 +16237,118 @@ export const useSimulateBeanstalk_SowWithReferral = functionName: 'sowWithReferral', }) +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCancelPodListing"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchCancelPodListing = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCancelPodListing', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCancelPodOrder"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchCancelPodOrder = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCancelPodOrder', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCreatePodListing"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchCreatePodListing = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCreatePodListing', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchFillPodListing"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchFillPodListing = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchFillPodListing', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchCreatePodOrder"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchCreatePodOrder = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchCreatePodOrder', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchFillPodOrder"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchFillPodOrder = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchFillPodOrder', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link beanstalkAbi}__ and `functionName` set to `"batchConvert"` + * + * - [__View Contract on Ethereum Etherscan__](https://etherscan.io/address/0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5) + * - + * - [__View Contract on Base Basescan__](https://basescan.org/address/0xD1A0D188E861ed9d15773a2F3574a2e94134bA8f) + * - + * - [__View Contract on Arbitrum One Arbiscan__](https://arbiscan.io/address/0xD1A0060ba708BC4BCD3DA6C37EFa8deDF015FB70) + */ +export const useSimulateBeanstalk_BatchConvert = + /*#__PURE__*/ createUseSimulateContract({ + abi: beanstalkAbi, + address: beanstalkAddress, + functionName: 'batchConvert', + }) + /** * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link beanstalkAbi}__ * diff --git a/src/generated/gql/pintostalk/gql.ts b/src/generated/gql/pintostalk/gql.ts index 508c651f8..e63e17bf9 100644 --- a/src/generated/gql/pintostalk/gql.ts +++ b/src/generated/gql/pintostalk/gql.ts @@ -26,6 +26,8 @@ type Documents = { "query AllPodListings($first: Int = 1000, $status: MarketStatus = ACTIVE, $maxHarvestableIndex: BigInt!, $skip: Int = 0) {\n podListings(\n first: $first\n skip: $skip\n where: {status: $status, maxHarvestableIndex_gt: $maxHarvestableIndex, remainingAmount_gt: \"100000\"}\n orderBy: index\n orderDirection: asc\n ) {\n ...PodListing\n }\n}": typeof types.AllPodListingsDocument, "query AllPodOrders($first: Int = 1000, $status: MarketStatus = ACTIVE, $skip: Int = 0) {\n podOrders(\n first: $first\n skip: $skip\n orderBy: createdAt\n orderDirection: desc\n where: {status: $status}\n ) {\n ...PodOrder\n }\n}": typeof types.AllPodOrdersDocument, "query FarmerMarketActivity($first: Int = 1000, $account: String!, $listings_createdAt_gt: BigInt, $orders_createdAt_gt: BigInt, $fill_createdAt_gt: BigInt) {\n podListings(\n first: $first\n where: {farmer: $account, createdAt_gt: $listings_createdAt_gt, status_not: FILLED_PARTIAL}\n ) {\n ...PodListing\n }\n podOrders(\n first: $first\n orderBy: createdAt\n orderDirection: desc\n where: {farmer: $account, createdAt_gt: $orders_createdAt_gt}\n ) {\n ...PodOrder\n }\n podFills(\n first: $first\n where: {and: [{createdAt_gt: $fill_createdAt_gt}, {or: [{fromFarmer: $account}, {toFarmer: $account}]}]}\n ) {\n ...PodFill\n }\n}": typeof types.FarmerMarketActivityDocument, + "query MyPodListings($first: Int = 100, $skip: Int = 0, $account: String!, $maxHarvestableIndex: BigInt!) {\n podListings(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE, maxHarvestableIndex_gt: $maxHarvestableIndex, remainingAmount_gt: \"100000\"}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodListing\n }\n}": typeof types.MyPodListingsDocument, + "query MyPodOrders($first: Int = 100, $skip: Int = 0, $account: String!) {\n podOrders(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodOrder\n }\n}": typeof types.MyPodOrdersDocument, "fragment PodFill on PodFill {\n id\n placeInLine\n amount\n index\n start\n costInBeans\n fromFarmer {\n id\n }\n toFarmer {\n id\n }\n listing {\n id\n originalAmount\n }\n order {\n id\n beanAmount\n }\n createdAt\n}": typeof types.PodFillFragmentDoc, "fragment PodListing on PodListing {\n id\n farmer {\n id\n }\n historyID\n index\n start\n mode\n pricingType\n pricePerPod\n pricingFunction\n maxHarvestableIndex\n minFillAmount\n originalIndex\n originalPlaceInLine\n originalAmount\n filled\n amount\n remainingAmount\n filledAmount\n fill {\n placeInLine\n }\n status\n createdAt\n updatedAt\n creationHash\n}": typeof types.PodListingFragmentDoc, "fragment PodOrder on PodOrder {\n id\n farmer {\n id\n }\n historyID\n pricingType\n pricePerPod\n pricingFunction\n maxPlaceInLine\n minFillAmount\n beanAmount\n podAmountFilled\n beanAmountFilled\n status\n createdAt\n updatedAt\n creationHash\n}": typeof types.PodOrderFragmentDoc, @@ -54,6 +56,8 @@ const documents: Documents = { "query AllPodListings($first: Int = 1000, $status: MarketStatus = ACTIVE, $maxHarvestableIndex: BigInt!, $skip: Int = 0) {\n podListings(\n first: $first\n skip: $skip\n where: {status: $status, maxHarvestableIndex_gt: $maxHarvestableIndex, remainingAmount_gt: \"100000\"}\n orderBy: index\n orderDirection: asc\n ) {\n ...PodListing\n }\n}": types.AllPodListingsDocument, "query AllPodOrders($first: Int = 1000, $status: MarketStatus = ACTIVE, $skip: Int = 0) {\n podOrders(\n first: $first\n skip: $skip\n orderBy: createdAt\n orderDirection: desc\n where: {status: $status}\n ) {\n ...PodOrder\n }\n}": types.AllPodOrdersDocument, "query FarmerMarketActivity($first: Int = 1000, $account: String!, $listings_createdAt_gt: BigInt, $orders_createdAt_gt: BigInt, $fill_createdAt_gt: BigInt) {\n podListings(\n first: $first\n where: {farmer: $account, createdAt_gt: $listings_createdAt_gt, status_not: FILLED_PARTIAL}\n ) {\n ...PodListing\n }\n podOrders(\n first: $first\n orderBy: createdAt\n orderDirection: desc\n where: {farmer: $account, createdAt_gt: $orders_createdAt_gt}\n ) {\n ...PodOrder\n }\n podFills(\n first: $first\n where: {and: [{createdAt_gt: $fill_createdAt_gt}, {or: [{fromFarmer: $account}, {toFarmer: $account}]}]}\n ) {\n ...PodFill\n }\n}": types.FarmerMarketActivityDocument, + "query MyPodListings($first: Int = 100, $skip: Int = 0, $account: String!, $maxHarvestableIndex: BigInt!) {\n podListings(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE, maxHarvestableIndex_gt: $maxHarvestableIndex, remainingAmount_gt: \"100000\"}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodListing\n }\n}": types.MyPodListingsDocument, + "query MyPodOrders($first: Int = 100, $skip: Int = 0, $account: String!) {\n podOrders(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodOrder\n }\n}": types.MyPodOrdersDocument, "fragment PodFill on PodFill {\n id\n placeInLine\n amount\n index\n start\n costInBeans\n fromFarmer {\n id\n }\n toFarmer {\n id\n }\n listing {\n id\n originalAmount\n }\n order {\n id\n beanAmount\n }\n createdAt\n}": types.PodFillFragmentDoc, "fragment PodListing on PodListing {\n id\n farmer {\n id\n }\n historyID\n index\n start\n mode\n pricingType\n pricePerPod\n pricingFunction\n maxHarvestableIndex\n minFillAmount\n originalIndex\n originalPlaceInLine\n originalAmount\n filled\n amount\n remainingAmount\n filledAmount\n fill {\n placeInLine\n }\n status\n createdAt\n updatedAt\n creationHash\n}": types.PodListingFragmentDoc, "fragment PodOrder on PodOrder {\n id\n farmer {\n id\n }\n historyID\n pricingType\n pricePerPod\n pricingFunction\n maxPlaceInLine\n minFillAmount\n beanAmount\n podAmountFilled\n beanAmountFilled\n status\n createdAt\n updatedAt\n creationHash\n}": types.PodOrderFragmentDoc, @@ -132,6 +136,14 @@ export function graphql(source: "query AllPodOrders($first: Int = 1000, $status: * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query FarmerMarketActivity($first: Int = 1000, $account: String!, $listings_createdAt_gt: BigInt, $orders_createdAt_gt: BigInt, $fill_createdAt_gt: BigInt) {\n podListings(\n first: $first\n where: {farmer: $account, createdAt_gt: $listings_createdAt_gt, status_not: FILLED_PARTIAL}\n ) {\n ...PodListing\n }\n podOrders(\n first: $first\n orderBy: createdAt\n orderDirection: desc\n where: {farmer: $account, createdAt_gt: $orders_createdAt_gt}\n ) {\n ...PodOrder\n }\n podFills(\n first: $first\n where: {and: [{createdAt_gt: $fill_createdAt_gt}, {or: [{fromFarmer: $account}, {toFarmer: $account}]}]}\n ) {\n ...PodFill\n }\n}"): (typeof documents)["query FarmerMarketActivity($first: Int = 1000, $account: String!, $listings_createdAt_gt: BigInt, $orders_createdAt_gt: BigInt, $fill_createdAt_gt: BigInt) {\n podListings(\n first: $first\n where: {farmer: $account, createdAt_gt: $listings_createdAt_gt, status_not: FILLED_PARTIAL}\n ) {\n ...PodListing\n }\n podOrders(\n first: $first\n orderBy: createdAt\n orderDirection: desc\n where: {farmer: $account, createdAt_gt: $orders_createdAt_gt}\n ) {\n ...PodOrder\n }\n podFills(\n first: $first\n where: {and: [{createdAt_gt: $fill_createdAt_gt}, {or: [{fromFarmer: $account}, {toFarmer: $account}]}]}\n ) {\n ...PodFill\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query MyPodListings($first: Int = 100, $skip: Int = 0, $account: String!, $maxHarvestableIndex: BigInt!) {\n podListings(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE, maxHarvestableIndex_gt: $maxHarvestableIndex, remainingAmount_gt: \"100000\"}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodListing\n }\n}"): (typeof documents)["query MyPodListings($first: Int = 100, $skip: Int = 0, $account: String!, $maxHarvestableIndex: BigInt!) {\n podListings(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE, maxHarvestableIndex_gt: $maxHarvestableIndex, remainingAmount_gt: \"100000\"}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodListing\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query MyPodOrders($first: Int = 100, $skip: Int = 0, $account: String!) {\n podOrders(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodOrder\n }\n}"): (typeof documents)["query MyPodOrders($first: Int = 100, $skip: Int = 0, $account: String!) {\n podOrders(\n first: $first\n skip: $skip\n where: {farmer: $account, status: ACTIVE}\n orderBy: createdAt\n orderDirection: desc\n ) {\n ...PodOrder\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/src/generated/gql/pintostalk/graphql.ts b/src/generated/gql/pintostalk/graphql.ts index 78aa7d75a..9b4ded273 100644 --- a/src/generated/gql/pintostalk/graphql.ts +++ b/src/generated/gql/pintostalk/graphql.ts @@ -14130,6 +14130,25 @@ export type FarmerMarketActivityQueryVariables = Exact<{ export type FarmerMarketActivityQuery = { __typename?: 'Query', podListings: Array<{ __typename?: 'PodListing', id: string, historyID: string, index: any, start: any, mode: number, pricingType?: number | null, pricePerPod: number, pricingFunction?: any | null, maxHarvestableIndex: any, minFillAmount: any, originalIndex: any, originalPlaceInLine: any, originalAmount: any, filled: any, amount: any, remainingAmount: any, filledAmount: any, status: MarketStatus, createdAt: any, updatedAt: any, creationHash: any, farmer: { __typename?: 'Farmer', id: any }, fill?: { __typename?: 'PodFill', placeInLine: any } | null }>, podOrders: Array<{ __typename?: 'PodOrder', id: string, historyID: string, pricingType?: number | null, pricePerPod: number, pricingFunction?: any | null, maxPlaceInLine: any, minFillAmount: any, beanAmount: any, podAmountFilled: any, beanAmountFilled: any, status: MarketStatus, createdAt: any, updatedAt: any, creationHash: any, farmer: { __typename?: 'Farmer', id: any } }>, podFills: Array<{ __typename?: 'PodFill', id: string, placeInLine: any, amount: any, index: any, start: any, costInBeans: any, createdAt: any, fromFarmer: { __typename?: 'Farmer', id: any }, toFarmer: { __typename?: 'Farmer', id: any }, listing?: { __typename?: 'PodListing', id: string, originalAmount: any } | null, order?: { __typename?: 'PodOrder', id: string, beanAmount: any } | null }> }; +export type MyPodListingsQueryVariables = Exact<{ + first?: InputMaybe; + skip?: InputMaybe; + account: Scalars['String']['input']; + maxHarvestableIndex: Scalars['BigInt']['input']; +}>; + + +export type MyPodListingsQuery = { __typename?: 'Query', podListings: Array<{ __typename?: 'PodListing', id: string, historyID: string, index: any, start: any, mode: number, pricingType?: number | null, pricePerPod: number, pricingFunction?: any | null, maxHarvestableIndex: any, minFillAmount: any, originalIndex: any, originalPlaceInLine: any, originalAmount: any, filled: any, amount: any, remainingAmount: any, filledAmount: any, status: MarketStatus, createdAt: any, updatedAt: any, creationHash: any, farmer: { __typename?: 'Farmer', id: any }, fill?: { __typename?: 'PodFill', placeInLine: any } | null }> }; + +export type MyPodOrdersQueryVariables = Exact<{ + first?: InputMaybe; + skip?: InputMaybe; + account: Scalars['String']['input']; +}>; + + +export type MyPodOrdersQuery = { __typename?: 'Query', podOrders: Array<{ __typename?: 'PodOrder', id: string, historyID: string, pricingType?: number | null, pricePerPod: number, pricingFunction?: any | null, maxPlaceInLine: any, minFillAmount: any, beanAmount: any, podAmountFilled: any, beanAmountFilled: any, status: MarketStatus, createdAt: any, updatedAt: any, creationHash: any, farmer: { __typename?: 'Farmer', id: any } }> }; + export type PodFillFragment = { __typename?: 'PodFill', id: string, placeInLine: any, amount: any, index: any, start: any, costInBeans: any, createdAt: any, fromFarmer: { __typename?: 'Farmer', id: any }, toFarmer: { __typename?: 'Farmer', id: any }, listing?: { __typename?: 'PodListing', id: string, originalAmount: any } | null, order?: { __typename?: 'PodOrder', id: string, beanAmount: any } | null }; export type PodListingFragment = { __typename?: 'PodListing', id: string, historyID: string, index: any, start: any, mode: number, pricingType?: number | null, pricePerPod: number, pricingFunction?: any | null, maxHarvestableIndex: any, minFillAmount: any, originalIndex: any, originalPlaceInLine: any, originalAmount: any, filled: any, amount: any, remainingAmount: any, filledAmount: any, status: MarketStatus, createdAt: any, updatedAt: any, creationHash: any, farmer: { __typename?: 'Farmer', id: any }, fill?: { __typename?: 'PodFill', placeInLine: any } | null }; @@ -14243,6 +14262,8 @@ export const AllMarketActivityDocument = {"kind":"Document","definitions":[{"kin export const AllPodListingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AllPodListings"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"1000"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MarketStatus"}},"defaultValue":{"kind":"EnumValue","value":"ACTIVE"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"maxHarvestableIndex"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"podListings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"maxHarvestableIndex_gt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"maxHarvestableIndex"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"remainingAmount_gt"},"value":{"kind":"StringValue","value":"100000","block":false}}]}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"index"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"asc"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodListing"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodListing"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodListing"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"farmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"historyID"}},{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"mode"}},{"kind":"Field","name":{"kind":"Name","value":"pricingType"}},{"kind":"Field","name":{"kind":"Name","value":"pricePerPod"}},{"kind":"Field","name":{"kind":"Name","value":"pricingFunction"}},{"kind":"Field","name":{"kind":"Name","value":"maxHarvestableIndex"}},{"kind":"Field","name":{"kind":"Name","value":"minFillAmount"}},{"kind":"Field","name":{"kind":"Name","value":"originalIndex"}},{"kind":"Field","name":{"kind":"Name","value":"originalPlaceInLine"}},{"kind":"Field","name":{"kind":"Name","value":"originalAmount"}},{"kind":"Field","name":{"kind":"Name","value":"filled"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"remainingAmount"}},{"kind":"Field","name":{"kind":"Name","value":"filledAmount"}},{"kind":"Field","name":{"kind":"Name","value":"fill"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"placeInLine"}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"creationHash"}}]}}]} as unknown as DocumentNode; export const AllPodOrdersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AllPodOrders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"1000"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MarketStatus"}},"defaultValue":{"kind":"EnumValue","value":"ACTIVE"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"podOrders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"createdAt"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"desc"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodOrder"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodOrder"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodOrder"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"farmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"historyID"}},{"kind":"Field","name":{"kind":"Name","value":"pricingType"}},{"kind":"Field","name":{"kind":"Name","value":"pricePerPod"}},{"kind":"Field","name":{"kind":"Name","value":"pricingFunction"}},{"kind":"Field","name":{"kind":"Name","value":"maxPlaceInLine"}},{"kind":"Field","name":{"kind":"Name","value":"minFillAmount"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmount"}},{"kind":"Field","name":{"kind":"Name","value":"podAmountFilled"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmountFilled"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"creationHash"}}]}}]} as unknown as DocumentNode; export const FarmerMarketActivityDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FarmerMarketActivity"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"1000"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"account"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"listings_createdAt_gt"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orders_createdAt_gt"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fill_createdAt_gt"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"podListings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"farmer"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"createdAt_gt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"listings_createdAt_gt"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"status_not"},"value":{"kind":"EnumValue","value":"FILLED_PARTIAL"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodListing"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podOrders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"createdAt"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"desc"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"farmer"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"createdAt_gt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orders_createdAt_gt"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodOrder"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podFills"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"and"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"createdAt_gt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fill_createdAt_gt"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"or"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"fromFarmer"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"toFarmer"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}}]}]}}]}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodFill"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodListing"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodListing"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"farmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"historyID"}},{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"mode"}},{"kind":"Field","name":{"kind":"Name","value":"pricingType"}},{"kind":"Field","name":{"kind":"Name","value":"pricePerPod"}},{"kind":"Field","name":{"kind":"Name","value":"pricingFunction"}},{"kind":"Field","name":{"kind":"Name","value":"maxHarvestableIndex"}},{"kind":"Field","name":{"kind":"Name","value":"minFillAmount"}},{"kind":"Field","name":{"kind":"Name","value":"originalIndex"}},{"kind":"Field","name":{"kind":"Name","value":"originalPlaceInLine"}},{"kind":"Field","name":{"kind":"Name","value":"originalAmount"}},{"kind":"Field","name":{"kind":"Name","value":"filled"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"remainingAmount"}},{"kind":"Field","name":{"kind":"Name","value":"filledAmount"}},{"kind":"Field","name":{"kind":"Name","value":"fill"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"placeInLine"}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"creationHash"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodOrder"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodOrder"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"farmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"historyID"}},{"kind":"Field","name":{"kind":"Name","value":"pricingType"}},{"kind":"Field","name":{"kind":"Name","value":"pricePerPod"}},{"kind":"Field","name":{"kind":"Name","value":"pricingFunction"}},{"kind":"Field","name":{"kind":"Name","value":"maxPlaceInLine"}},{"kind":"Field","name":{"kind":"Name","value":"minFillAmount"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmount"}},{"kind":"Field","name":{"kind":"Name","value":"podAmountFilled"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmountFilled"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"creationHash"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodFill"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodFill"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"placeInLine"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"costInBeans"}},{"kind":"Field","name":{"kind":"Name","value":"fromFarmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toFarmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"listing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"originalAmount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; +export const MyPodListingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyPodListings"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"100"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"account"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"maxHarvestableIndex"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"podListings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"farmer"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"status"},"value":{"kind":"EnumValue","value":"ACTIVE"}},{"kind":"ObjectField","name":{"kind":"Name","value":"maxHarvestableIndex_gt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"maxHarvestableIndex"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"remainingAmount_gt"},"value":{"kind":"StringValue","value":"100000","block":false}}]}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"createdAt"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"desc"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodListing"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodListing"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodListing"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"farmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"historyID"}},{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"mode"}},{"kind":"Field","name":{"kind":"Name","value":"pricingType"}},{"kind":"Field","name":{"kind":"Name","value":"pricePerPod"}},{"kind":"Field","name":{"kind":"Name","value":"pricingFunction"}},{"kind":"Field","name":{"kind":"Name","value":"maxHarvestableIndex"}},{"kind":"Field","name":{"kind":"Name","value":"minFillAmount"}},{"kind":"Field","name":{"kind":"Name","value":"originalIndex"}},{"kind":"Field","name":{"kind":"Name","value":"originalPlaceInLine"}},{"kind":"Field","name":{"kind":"Name","value":"originalAmount"}},{"kind":"Field","name":{"kind":"Name","value":"filled"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"remainingAmount"}},{"kind":"Field","name":{"kind":"Name","value":"filledAmount"}},{"kind":"Field","name":{"kind":"Name","value":"fill"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"placeInLine"}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"creationHash"}}]}}]} as unknown as DocumentNode; +export const MyPodOrdersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyPodOrders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"100"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"account"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"podOrders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"farmer"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"status"},"value":{"kind":"EnumValue","value":"ACTIVE"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"createdAt"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"desc"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PodOrder"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PodOrder"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PodOrder"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"farmer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"historyID"}},{"kind":"Field","name":{"kind":"Name","value":"pricingType"}},{"kind":"Field","name":{"kind":"Name","value":"pricePerPod"}},{"kind":"Field","name":{"kind":"Name","value":"pricingFunction"}},{"kind":"Field","name":{"kind":"Name","value":"maxPlaceInLine"}},{"kind":"Field","name":{"kind":"Name","value":"minFillAmount"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmount"}},{"kind":"Field","name":{"kind":"Name","value":"podAmountFilled"}},{"kind":"Field","name":{"kind":"Name","value":"beanAmountFilled"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"creationHash"}}]}}]} as unknown as DocumentNode; export const FarmerReferralDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FarmerReferral"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"farmer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"totalReferralRewardPodsReceived"}},{"kind":"Field","name":{"kind":"Name","value":"refereeCount"}}]}}]}}]} as unknown as DocumentNode; export const ReferralLeaderboardDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ReferralLeaderboard"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"block"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Block_height"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"farmers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"totalReferralRewardPodsReceived"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"desc"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"totalReferralRewardPodsReceived_gt"},"value":{"kind":"StringValue","value":"0","block":false}}]}},{"kind":"Argument","name":{"kind":"Name","value":"block"},"value":{"kind":"Variable","name":{"kind":"Name","value":"block"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"refereeCount"}},{"kind":"Field","name":{"kind":"Name","value":"totalReferralRewardPodsReceived"}}]}}]}}]} as unknown as DocumentNode; export const FarmerSeasonalSiloDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FarmerSeasonalSilo"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"from"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"to"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"account"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"siloHourlySnapshots"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"silo"},"value":{"kind":"Variable","name":{"kind":"Name","value":"account"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"season_gte"},"value":{"kind":"Variable","name":{"kind":"Name","value":"from"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"season_lte"},"value":{"kind":"Variable","name":{"kind":"Name","value":"to"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"season"}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"EnumValue","value":"asc"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"season"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"plantedBeans"}},{"kind":"Field","name":{"kind":"Name","value":"stalk"}},{"kind":"Field","name":{"kind":"Name","value":"germinatingStalk"}},{"kind":"Field","name":{"kind":"Name","value":"depositedBDV"}}]}}]}}]} as unknown as DocumentNode; diff --git a/src/lib/claim/depositUtils.ts b/src/lib/claim/depositUtils.ts index 923812fdf..0130b505c 100644 --- a/src/lib/claim/depositUtils.ts +++ b/src/lib/claim/depositUtils.ts @@ -3,7 +3,7 @@ import { DepositGroup } from "@/components/CombineSelect"; import { siloHelpersABI } from "@/constants/abi/SiloHelpersABI"; import { tractorHelpersABI } from "@/constants/abi/TractorHelpersABI"; import { SILO_HELPERS_ADDRESS, TRACTOR_HELPERS_ADDRESS } from "@/constants/address"; -import convert from "@/encoders/silo/convert"; +import batchConvert, { type BatchConvertParams } from "@/encoders/batchConvert"; import { beanstalkAbi } from "@/generated/contractHooks"; import { calculateConvertData } from "@/utils/convert"; import { Token, TokenDepositData } from "@/utils/types"; @@ -133,7 +133,8 @@ export function generateCombineAndL2LCallData(farmerDeposits: Map token.isWhitelisted) - .flatMap(([token, depositData]) => encodeClaimRewardCombineCalls(depositData.deposits, token)); + .map(([token, depositData]) => encodeClaimRewardCombineCalls(depositData.deposits, token)) + .filter((call): call is `0x${string}` => call !== undefined); } /** @@ -547,44 +548,63 @@ export function createSmartGroups(deposits: DepositData[], targetGroups: number return newGroups; } +/** + * Encodes deposit combine operations for manual combining using batchConvert. + * Groups deposits and encodes all groups as a single batchConvert call. + * + * @param validGroups Array of deposit groups to combine + * @param token The token to combine deposits for + * @param deposits Array of all farmer deposits for the token + * @returns Single encoded batchConvert calldata, or undefined if no groups need combining + * + * @see encodeClaimRewardCombineCalls for automatic claim-time combining + */ export function encodeGroupCombineCalls( validGroups: DepositGroup[], token: Token, deposits: DepositData[], -): `0x${string}`[] { +): `0x${string}` | undefined { // Exclude groups with only one deposit, since they don't need combining const groupsToEncode = validGroups.filter((group) => group.deposits.length > 1); - return groupsToEncode.map((group) => { - // Get selected deposits for this group + if (groupsToEncode.length === 0) return undefined; + + // Build BatchConvertParams for ALL groups + const batchParams: BatchConvertParams[] = groupsToEncode.map((group) => { const selectedDepositData = group.deposits .map((stem) => deposits.find((d) => d.stem.toHuman() === stem)) - .filter(Boolean); + .filter((d): d is DepositData => d !== undefined); const totalAmount = selectedDepositData.reduce((sum, deposit) => { - if (!deposit) return sum; return deposit.amount.add(sum); }, TokenValue.ZERO); const convertData = calculateConvertData(token, token, totalAmount, totalAmount); if (!convertData) throw new Error("Failed to prepare combine data"); - const stems = selectedDepositData.filter((d): d is DepositData => d !== undefined).map((d) => d.stem.toBigInt()); - const amounts = selectedDepositData - .filter((d): d is DepositData => d !== undefined) - .map((d) => d.amount.toBigInt()); + const stems = selectedDepositData.map((d) => d.stem.toBigInt()); + const amounts = selectedDepositData.map((d) => d.amount.toBigInt()); - // Use the imported convert function instead - return convert(convertData, stems, amounts).callData; + return { convertData, stems, amounts, grownStalkSlippage: 0n }; }); + + // Return SINGLE batchConvert call with all groups + return batchConvert(batchParams); } -// Add a new function to handle claim reward grouping and encoding +/** + * Encodes deposit combine operations for a single token using batchConvert. + * Groups deposits by stalk/BDV ratio and encodes all groups as a single batchConvert call. + * @param deposits Array of deposit data for the token + * @param token The token to combine deposits for + * @param targetGroups Number of groups to create (default 20) + * @returns Single encoded batchConvert calldata, or undefined if no groups need combining + */ export function encodeClaimRewardCombineCalls( deposits: DepositData[], token: Token, targetGroups: number = 20, -): `0x${string}`[] { +): `0x${string}` | undefined { // Use our existing smart grouping logic const groups = createSmartGroups(deposits, targetGroups); @@ -598,7 +618,6 @@ export function encodeClaimRewardCombineCalls( const totalBdv = groupDeposits.reduce((sum, deposit) => sum.add(deposit.depositBdv), TokenValue.ZERO); - // Calculate the stalk-to-BDV ratio for the entire group const stalkPerBdv = totalBdv.gt(0) ? totalStalk.div(totalBdv) : TokenValue.ZERO; return { @@ -610,14 +629,30 @@ export function encodeClaimRewardCombineCalls( // Sort by Stalk/BDV ratio (highest to lowest) const sortedGroups = groupsWithRatio .sort((a, b) => b.stalkPerBdv.sub(a.stalkPerBdv).toNumber()) - .map(({ id, deposits, stalkPerBdv }) => ({ id, deposits, stalkPerBdv })); + .map(({ id, deposits }) => ({ id, deposits })); - // Use our existing encode function with sorted groups - strip stalkPerBdv before passing - const result = encodeGroupCombineCalls( - sortedGroups.map(({ id, deposits }) => ({ id, deposits })), - token, - deposits, - ); + // Build BatchConvertParams for each group with >1 deposit + const batchParams: BatchConvertParams[] = sortedGroups + .filter((group) => group.deposits.length > 1) + .map((group) => { + const selectedDepositData = group.deposits + .map((stem) => deposits.find((d) => d.stem.toHuman() === stem)) + .filter((d): d is DepositData => d !== undefined); + + const totalAmount = selectedDepositData.reduce((sum, deposit) => { + return deposit.amount.add(sum); + }, TokenValue.ZERO); + + const convertData = calculateConvertData(token, token, totalAmount, totalAmount); + if (!convertData) throw new Error("Failed to prepare combine data"); + + const stems = selectedDepositData.map((d) => d.stem.toBigInt()); + const amounts = selectedDepositData.map((d) => d.amount.toBigInt()); + + return { convertData, stems, amounts, grownStalkSlippage: 0n }; + }); + + if (batchParams.length === 0) return undefined; - return result; + return batchConvert(batchParams); } diff --git a/src/pages/Market.tsx b/src/pages/Market.tsx index 229afc2c6..dc259adf2 100644 --- a/src/pages/Market.tsx +++ b/src/pages/Market.tsx @@ -22,9 +22,12 @@ import { ActiveElement, ChartEvent, PointStyle, TooltipOptions } from "chart.js" import { Chart } from "chart.js"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; +import { useAccount } from "wagmi"; import { AllActivityTable } from "./market/AllActivityTable"; import { FarmerActivityTable } from "./market/FarmerActivityTable"; import MarketModeSelect from "./market/MarketModeSelect"; +import { MyListingsTable } from "./market/MyListingsTable"; +import { MyOrdersTable } from "./market/MyOrdersTable"; import { PodListingsTable } from "./market/PodListingsTable"; import { PodOrdersTable } from "./market/PodOrdersTable"; import CreateListing, { PodListingData } from "./market/actions/CreateListing"; @@ -33,8 +36,8 @@ import FillListing from "./market/actions/FillListing"; import FillOrder from "./market/actions/FillOrder"; // Constants -const TABLE_SLUGS = ["activity", "listings", "orders", "my-activity"]; -const TABLE_LABELS = ["Activity", "Listings", "Orders", "My Activity"]; +const TABLE_SLUGS = ["activity", "listings", "orders", "my-activity", "my-listings", "my-orders"]; +const TABLE_LABELS = ["Activity", "Listings", "Orders", "My Activity", "My Listings", "My Orders"]; const SELECTED_PLOT_PURPLE_COLOR = "#8B5CF6"; const SELECTED_PLOT_BORDER_WIDTH = 1.75; @@ -220,6 +223,9 @@ export function Market() { const chartXMax = Math.round((podLineAsNumber / 10) * 10); const harvestableIndex = useHarvestableIndex(); const navHeight = useNavHeight(); + const account = useAccount(); + const [selectedListingIds, setSelectedListingIds] = useState([]); + const [selectedOrderIds, setSelectedOrderIds] = useState([]); const [mounted, setMounted] = useState(false); const [selectedPlotData, setSelectedPlotData] = useState<{ @@ -1040,7 +1046,7 @@ export function Market() { {TABLE_SLUGS.map((s, idx) => (

{TABLE_LABELS[idx]} @@ -1053,6 +1059,20 @@ export function Market() { {tab === TABLE_SLUGS[1] && } {tab === TABLE_SLUGS[2] && } {tab === TABLE_SLUGS[3] && } + {tab === TABLE_SLUGS[4] && ( + + )} + {tab === TABLE_SLUGS[5] && ( + + )}

void; +} + +export function MyListingsTable({ address, selectedIds = [], onSelectionChange }: MyListingsTableProps) { + const BEAN = useTokenData().mainToken; + const harvestableIndex = useHarvestableIndex(); + + // Fetch user's listings via GraphQL hook + const { listings, isLoading } = useMyPodListings({ account: address }); + + const rowsPerPage = 12; + const totalRows = listings?.length || 0; + const totalPages = Math.ceil(totalRows / rowsPerPage); + const [currentPage, setCurrentPage] = useState(1); + const newestEventOnPage = rowsPerPage * currentPage - rowsPerPage; + const oldestEventOnPage = rowsPerPage * currentPage - 1; + + // Selection is enabled when onSelectionChange callback is provided + const selectable = !!onSelectionChange; + + // Immediate cancellation state + const [cancellingIds, setCancellingIds] = useState>(new Set()); + + const diamondAddress = useProtocolAddress(); + const queryClient = useQueryClient(); + const { allPodListings, allMarket, farmerMarket } = useQueryKeys({ + account: address, + harvestableIndex, + }); + + const onCancelSuccess = useCallback(() => { + queryClient.invalidateQueries({ queryKey: allPodListings }); + queryClient.invalidateQueries({ queryKey: allMarket }); + queryClient.invalidateQueries({ queryKey: farmerMarket }); + if (onSelectionChange) { + onSelectionChange([]); + } + }, [queryClient, allPodListings, allMarket, farmerMarket, onSelectionChange]); + + const { writeWithEstimateGas, submitting, setSubmitting } = useTransaction({ + successMessage: "Listing(s) cancelled successfully", + errorMessage: "Failed to cancel listing(s)", + successCallback: onCancelSuccess, + }); + + // Handle immediate single cancel + const handleCancelImmediate = useCallback( + async (listing: MarketplacePodListing) => { + if (!address) { + toast.error("Wallet not connected"); + return; + } + + setSubmitting(true); + setCancellingIds((prev) => new Set(prev).add(listing.id)); + + try { + trackSimpleEvent(ANALYTICS_EVENTS.MARKET.POD_LIST_CANCEL, { + listing_count: 1, + is_batch: false, + }); + + await writeWithEstimateGas({ + address: diamondAddress, + abi: beanstalkAbi, + functionName: "cancelPodListing", + args: [0n, TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt()], + }); + } finally { + setSubmitting(false); + setCancellingIds((prev) => { + const next = new Set(prev); + next.delete(listing.id); + return next; + }); + } + }, + [address, diamondAddress, writeWithEstimateGas, setSubmitting], + ); + + // Handle immediate bulk cancel + const handleBulkCancelImmediate = useCallback(async () => { + if (!address) { + toast.error("Wallet not connected"); + return; + } + + const listingsToCancel = listings?.filter((l) => selectedIds.includes(l.id)) || []; + const ownedListings = listingsToCancel.filter((l) => l.farmer.id.toLowerCase() === address.toLowerCase()); + + if (ownedListings.length === 0) { + toast.error("No owned listings to cancel"); + return; + } + + setSubmitting(true); + + try { + trackSimpleEvent(ANALYTICS_EVENTS.MARKET.POD_LIST_CANCEL, { + listing_count: ownedListings.length, + is_batch: true, + }); + + const batchArgs = ownedListings.map((listing) => ({ + fieldId: 0n, + index: TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt(), + })); + + await writeWithEstimateGas({ + address: diamondAddress, + abi: beanstalkAbi, + functionName: "batchCancelPodListing", + args: [batchArgs], + }); + } catch (error) { + console.error("Batch cancel failed:", error); + } finally { + setSubmitting(false); + } + }, [address, listings, selectedIds, diamondAddress, writeWithEstimateGas, setSubmitting]); + + // Compute visible listings on current page for select all logic + const visibleListings = listings?.slice(newestEventOnPage, oldestEventOnPage + 1) || []; + const visibleIds = visibleListings.map((l) => l.id); + const allVisibleSelected = visibleIds.length > 0 && visibleIds.every((id) => selectedIds.includes(id)); + const someVisibleSelected = visibleIds.some((id) => selectedIds.includes(id)) && !allVisibleSelected; + + // Handle "Select All" checkbox for visible listings on current page + const handleSelectAllChange = useCallback( + (checked: boolean) => { + if (!onSelectionChange) return; + if (checked) { + // Add all visible IDs that aren't already selected + const newSelection = [...selectedIds]; + for (const id of visibleIds) { + if (!newSelection.includes(id)) { + newSelection.push(id); + } + } + onSelectionChange(newSelection); + } else { + // Remove only the visible IDs from selection + onSelectionChange(selectedIds.filter((id) => !visibleIds.includes(id))); + } + }, + [selectedIds, visibleIds, onSelectionChange], + ); + + // Handle checkbox change for a single row + const handleCheckboxChange = useCallback( + (listingId: string, checked: boolean) => { + if (!onSelectionChange) return; + if (checked) { + onSelectionChange([...selectedIds, listingId]); + } else { + onSelectionChange(selectedIds.filter((id) => id !== listingId)); + } + }, + [selectedIds, onSelectionChange], + ); + + return ( + + +
+

Your active Pod Listings

+ {isLoading && } +
+
+ + {selectable && selectedIds.length > 0 && ( +
+ +
+ )} + + <> + + + {selectable && ( + + handleSelectAllChange(checked === true)} + aria-label="Select all visible listings" + /> + + )} + Created At + Amount + Place In Line + Price + Fill % + Expires In + + + + + {(!listings || listings.length === 0) && !isLoading && ( + + You have no active listings + + )} + {listings?.map((listing, i) => { + const dateOptions: Intl.DateTimeFormatOptions = { + year: "2-digit", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + hourCycle: "h24", + }; + const createdAt = new Date(Number(listing.createdAt) * 1000); + const originalAmount = parseFloat(listing.originalAmount); + const remainingAmount = parseFloat(listing.remainingAmount); + const fillPct = (originalAmount - remainingAmount) / originalAmount; + if (i >= newestEventOnPage && i <= oldestEventOnPage) + return ( + + {selectable && ( + + handleCheckboxChange(listing.id, checked === true)} + onClick={(e) => e.stopPropagation()} + aria-label={`Select listing ${listing.id}`} + /> + + )} + {createdAt.toLocaleString(undefined, dateOptions)} + +
+ + {TokenValue.fromBlockchain(listing.amount, PODS.decimals).toHuman("short")} +
+
+ + {TokenValue.fromBlockchain(listing.index, PODS.decimals).sub(harvestableIndex).toHuman("short")} + + +
+ + {TokenValue.fromBlockchain(listing.pricePerPod, BEAN.decimals).toHuman()} +
+
+ {formatter.pct(fillPct * 100)} + + {TokenValue.fromBlockchain(listing.maxHarvestableIndex, PODS.decimals) + .sub(harvestableIndex) + .toHuman("short")}{" "} + PODS + + + + +
+ ); + })} +
+ +
+ {totalPages > 1 && ( + + )} +
+
+ ); +} diff --git a/src/pages/market/MyOrdersTable.tsx b/src/pages/market/MyOrdersTable.tsx new file mode 100644 index 000000000..0f710d6d8 --- /dev/null +++ b/src/pages/market/MyOrdersTable.tsx @@ -0,0 +1,332 @@ +import podIcon from "@/assets/protocol/Pod.png"; +import pintoIcon from "@/assets/tokens/PINTO.png"; +import { TokenValue } from "@/classes/TokenValue"; +import FrameAnimator from "@/components/LoadingSpinner"; +import { MarketPaginationControls } from "@/components/MarketPaginationControls"; +import { Card, CardContent, CardHeader } from "@/components/ui/Card"; +import { Checkbox } from "@/components/ui/Checkbox"; +import IconImage from "@/components/ui/IconImage"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/Table"; +import { ANALYTICS_EVENTS } from "@/constants/analytics-events"; +import { PODS } from "@/constants/internalTokens"; +import { beanstalkAbi } from "@/generated/contractHooks"; +import { MyPodOrdersQuery } from "@/generated/gql/pintostalk/graphql"; +import { useProtocolAddress } from "@/hooks/pinto/useProtocolAddress"; +import useTransaction from "@/hooks/useTransaction"; +import useMyPodOrders from "@/state/market/useMyPodOrders"; +import { useQueryKeys } from "@/state/useQueryKeys"; +import useTokenData from "@/state/useTokenData"; +import { trackSimpleEvent } from "@/utils/analytics"; +import { formatter } from "@/utils/format"; +import { FarmToMode } from "@/utils/types"; +import { useQueryClient } from "@tanstack/react-query"; +import { useCallback, useState } from "react"; +import { toast } from "sonner"; + +export type MarketplacePodOrder = MyPodOrdersQuery["podOrders"][number]; + +export interface MyOrdersTableProps { + /** Connected wallet address */ + address: string | undefined; + /** IDs of selected orders */ + selectedIds?: string[]; + /** Callback when selection changes */ + onSelectionChange?: (selectedIds: string[]) => void; +} + +export function MyOrdersTable({ address, selectedIds = [], onSelectionChange }: MyOrdersTableProps) { + const { orders = [], isLoading } = useMyPodOrders({ account: address }); + const BEAN = useTokenData().mainToken; + + const rowsPerPage = 12; + const totalRows = orders?.length || 0; + const totalPages = Math.ceil(totalRows / rowsPerPage); + const [currentPage, setCurrentPage] = useState(1); + const newestEventOnPage = rowsPerPage * currentPage - rowsPerPage; + const oldestEventOnPage = rowsPerPage * currentPage - 1; + + // Selection is enabled when onSelectionChange callback is provided + const selectable = !!onSelectionChange; + + // Immediate cancellation state + const [cancellingIds, setCancellingIds] = useState>(new Set()); + + const diamondAddress = useProtocolAddress(); + const queryClient = useQueryClient(); + const { allPodOrders, allMarket, farmerMarket } = useQueryKeys({ + account: address, + }); + + const onCancelSuccess = useCallback(() => { + queryClient.invalidateQueries({ queryKey: allPodOrders }); + queryClient.invalidateQueries({ queryKey: allMarket }); + queryClient.invalidateQueries({ queryKey: farmerMarket }); + if (onSelectionChange) { + onSelectionChange([]); + } + }, [queryClient, allPodOrders, allMarket, farmerMarket, onSelectionChange]); + + const { writeWithEstimateGas, submitting, setSubmitting } = useTransaction({ + successMessage: "Order(s) cancelled successfully", + errorMessage: "Failed to cancel order(s)", + successCallback: onCancelSuccess, + }); + + // Handle immediate single cancel + const handleCancelImmediate = useCallback( + async (order: MarketplacePodOrder) => { + if (!address) { + toast.error("Wallet not connected"); + return; + } + + setSubmitting(true); + setCancellingIds((prev) => new Set(prev).add(order.id)); + + try { + trackSimpleEvent(ANALYTICS_EVENTS.MARKET.POD_ORDER_CANCEL, { + order_count: 1, + is_batch: false, + destination_mode: "wallet", + }); + + const maxPlaceInLine = TokenValue.fromBlockchain(order.maxPlaceInLine.toString(), PODS.decimals); + const pricePerPod = TokenValue.fromBlockchain(order.pricePerPod.toString(), BEAN.decimals); + const minFillAmount = TokenValue.fromBlockchain(order.minFillAmount.toString(), PODS.decimals); + + await writeWithEstimateGas({ + address: diamondAddress, + abi: beanstalkAbi, + functionName: "cancelPodOrder", + args: [ + { + orderer: address, + fieldId: 0n, + pricePerPod, + maxPlaceInLine, + minFillAmount, + }, + Number(FarmToMode.EXTERNAL), + ], + }); + } finally { + setSubmitting(false); + setCancellingIds((prev) => { + const next = new Set(prev); + next.delete(order.id); + return next; + }); + } + }, + [address, BEAN.decimals, diamondAddress, writeWithEstimateGas, setSubmitting], + ); + + // Handle immediate bulk cancel + const handleBulkCancelImmediate = useCallback(async () => { + if (!address) { + toast.error("Wallet not connected"); + return; + } + + const ordersToCancel = orders?.filter((o) => selectedIds.includes(o.id)) || []; + const ownedOrders = ordersToCancel.filter((o) => o.farmer.id.toLowerCase() === address.toLowerCase()); + + if (ownedOrders.length === 0) { + toast.error("No owned orders to cancel"); + return; + } + + setSubmitting(true); + + try { + trackSimpleEvent(ANALYTICS_EVENTS.MARKET.POD_ORDER_CANCEL, { + order_count: ownedOrders.length, + is_batch: true, + destination_mode: "wallet", + }); + + const batchArgs = ownedOrders.map((order) => ({ + orderer: address, + fieldId: 0n, + pricePerPod: TokenValue.fromBlockchain(order.pricePerPod.toString(), BEAN.decimals), + maxPlaceInLine: TokenValue.fromBlockchain(order.maxPlaceInLine.toString(), PODS.decimals), + minFillAmount: TokenValue.fromBlockchain(order.minFillAmount.toString(), PODS.decimals), + })); + + await writeWithEstimateGas({ + address: diamondAddress, + abi: beanstalkAbi, + functionName: "batchCancelPodOrder", + args: [batchArgs, Number(FarmToMode.EXTERNAL)], + }); + } catch (error) { + console.error("Batch cancel failed:", error); + } finally { + setSubmitting(false); + } + }, [address, orders, selectedIds, BEAN.decimals, diamondAddress, writeWithEstimateGas, setSubmitting]); + + // Compute visible orders on current page for select all logic + const visibleOrders = orders?.slice(newestEventOnPage, oldestEventOnPage + 1) || []; + const visibleIds = visibleOrders.map((o) => o.id); + const allVisibleSelected = visibleIds.length > 0 && visibleIds.every((id) => selectedIds.includes(id)); + const someVisibleSelected = visibleIds.some((id) => selectedIds.includes(id)) && !allVisibleSelected; + + // Handle "Select All" checkbox for visible orders on current page + const handleSelectAllChange = useCallback( + (checked: boolean) => { + if (!onSelectionChange) return; + if (checked) { + const newSelection = [...selectedIds]; + for (const id of visibleIds) { + if (!newSelection.includes(id)) { + newSelection.push(id); + } + } + onSelectionChange(newSelection); + } else { + onSelectionChange(selectedIds.filter((id) => !visibleIds.includes(id))); + } + }, + [selectedIds, visibleIds, onSelectionChange], + ); + + // Handle checkbox change for a single row + const handleCheckboxChange = useCallback( + (orderId: string, checked: boolean) => { + if (!onSelectionChange) return; + if (checked) { + onSelectionChange([...selectedIds, orderId]); + } else { + onSelectionChange(selectedIds.filter((id) => id !== orderId)); + } + }, + [selectedIds, onSelectionChange], + ); + + return ( + + +
+

Your active Pod Orders

+ {isLoading && } +
+
+ + {selectable && selectedIds.length > 0 && ( +
+ +
+ )} + + <> + + + {selectable && ( + + handleSelectAllChange(checked === true)} + aria-label="Select all visible orders" + /> + + )} + Created At + Amount + Place In Line + Price + Fill % + + + + + {(!orders || orders.length === 0) && !isLoading && ( + + You have no active orders + + )} + {orders?.map((order, i) => { + const dateOptions: Intl.DateTimeFormatOptions = { + year: "2-digit", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + hourCycle: "h24", + }; + const createdAt = new Date(Number(order.createdAt) * 1000); + const amount = TokenValue.fromBlockchain(order.beanAmount, BEAN.decimals); + const amountFilled = TokenValue.fromBlockchain(order.beanAmountFilled, BEAN.decimals); + const pricePerPod = TokenValue.fromBlockchain(order.pricePerPod, BEAN.decimals); + const remainingPods = amount.sub(amountFilled).div(pricePerPod); + const fillPct = amountFilled.div(amount).mul(100); + if (i >= newestEventOnPage && i <= oldestEventOnPage) + return ( + + {selectable && ( + + handleCheckboxChange(order.id, checked === true)} + onClick={(e) => e.stopPropagation()} + aria-label={`Select order ${order.id}`} + /> + + )} + {createdAt.toLocaleString(undefined, dateOptions)} + +
+ + {remainingPods.toHuman("short")} +
+
+ + 0 - {TokenValue.fromBlockchain(order.maxPlaceInLine, PODS.decimals).toHuman("short")} + + +
+ + {formatter.number(pricePerPod.toNumber(), { minDecimals: 2, maxDecimals: 2 })} +
+
+ {`${fillPct?.toHuman("short")}%`} + + + +
+ ); + })} +
+ +
+ {totalPages > 1 && ( + + )} +
+
+ ); +} diff --git a/src/pages/market/PodListingsTable.tsx b/src/pages/market/PodListingsTable.tsx index 35d750e2f..345550108 100644 --- a/src/pages/market/PodListingsTable.tsx +++ b/src/pages/market/PodListingsTable.tsx @@ -3,7 +3,7 @@ import pintoIcon from "@/assets/tokens/PINTO.png"; import { TokenValue } from "@/classes/TokenValue"; import FrameAnimator from "@/components/LoadingSpinner"; import { MarketPaginationControls } from "@/components/MarketPaginationControls"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/Card"; +import { Card, CardContent, CardHeader } from "@/components/ui/Card"; import IconImage from "@/components/ui/IconImage"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/Table"; import { PODS } from "@/constants/internalTokens"; @@ -84,7 +84,6 @@ export function PodListingsTable() { day: "2-digit", hour: "2-digit", minute: "2-digit", - // second: "2-digit", hourCycle: "h24", }; const createdAt = new Date(Number(listing.createdAt) * 1000); diff --git a/src/pages/market/actions/CancelListing.tsx b/src/pages/market/actions/CancelListing.tsx index 032308f97..f4003b49e 100644 --- a/src/pages/market/actions/CancelListing.tsx +++ b/src/pages/market/actions/CancelListing.tsx @@ -1,5 +1,6 @@ import { TokenValue } from "@/classes/TokenValue"; import SmartSubmitButton from "@/components/SmartSubmitButton"; +import { ANALYTICS_EVENTS } from "@/constants/analytics-events"; import { PODS } from "@/constants/internalTokens"; import { beanstalkAbi } from "@/generated/contractHooks"; import { AllPodListingsQuery } from "@/generated/gql/pintostalk/graphql"; @@ -7,17 +8,23 @@ import { useProtocolAddress } from "@/hooks/pinto/useProtocolAddress"; import useTransaction from "@/hooks/useTransaction"; import { useHarvestableIndex } from "@/state/useFieldData"; import { useQueryKeys } from "@/state/useQueryKeys"; +import { trackSimpleEvent } from "@/utils/analytics"; import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import { useAccount } from "wagmi"; +export type MarketplacePodListing = AllPodListingsQuery["podListings"][number]; + export interface CancelListingProps { - listing: AllPodListingsQuery["podListings"][number]; + /** Array of listings available for cancellation */ + listings: MarketplacePodListing[]; + /** Optional array of listing IDs to cancel. If not provided, cancels all listings */ + selectedListingIds?: string[]; } -export default function CancelListing({ listing }: CancelListingProps) { +export default function CancelListing({ listings, selectedListingIds }: CancelListingProps) { const diamondAddress = useProtocolAddress(); const account = useAccount(); const harvestableIndex = useHarvestableIndex(); @@ -30,49 +37,86 @@ export default function CancelListing({ listing }: CancelListingProps) { }); const allQK = useMemo(() => [allPodListings, allMarket, farmerMarket], [allPodListings, allMarket, farmerMarket]); + // Filter listings by selectedListingIds if provided, otherwise use all listings + const listingsToCancel = useMemo(() => { + if (selectedListingIds && selectedListingIds.length > 0) { + return listings.filter((listing) => selectedListingIds.includes(listing.id)); + } + return listings; + }, [listings, selectedListingIds]); + + const cancelCount = listingsToCancel.length; + const isBatch = cancelCount > 1; + const onSuccess = useCallback(() => { navigate(`/market/pods/sell`); allQK.forEach((key) => queryClient.invalidateQueries({ queryKey: key })); }, [navigate, queryClient, allQK]); const { writeWithEstimateGas, submitting, isConfirming, setSubmitting } = useTransaction({ - successMessage: "Cancel Listing successful", - errorMessage: "Cancel Listing failed", + successMessage: isBatch ? `Cancelled ${cancelCount} Listings` : "Cancel Listing successful", + errorMessage: isBatch ? "Batch Cancel Listings failed" : "Cancel Listing failed", successCallback: onSuccess, }); const onSubmit = useCallback(() => { + if (cancelCount === 0) return; + try { setSubmitting(true); - toast.loading("Cancelling Listing..."); + toast.loading(isBatch ? `Cancelling ${cancelCount} Listings...` : "Cancelling Listing..."); + + trackSimpleEvent(ANALYTICS_EVENTS.MARKET.POD_LIST_CANCEL, { + listing_count: cancelCount, + is_batch: isBatch, + }); + + // Single listing: use original cancelPodListing function + if (!isBatch) { + const listing = listingsToCancel[0]; + return writeWithEstimateGas({ + address: diamondAddress, + abi: beanstalkAbi, + functionName: "cancelPodListing", + args: [ + 0n, // fieldId + TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt(), // index + ], + }); + } + + // Multiple listings: use batchCancelPodListing + const batchArgs = listingsToCancel.map((listing) => ({ + fieldId: 0n, + index: TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt(), + })); + return writeWithEstimateGas({ address: diamondAddress, abi: beanstalkAbi, - functionName: "cancelPodListing", - args: [ - 0n, // fieldId - TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt(), // index - ], + functionName: "batchCancelPodListing", + args: [batchArgs], }); } catch (e) { console.error(e); toast.dismiss(); - toast.error("Cancel Listing Failed"); + toast.error(isBatch ? "Batch Cancel Listings Failed" : "Cancel Listing Failed"); throw e; } finally { setSubmitting(false); } - }, [listing, diamondAddress, setSubmitting, writeWithEstimateGas]); + }, [cancelCount, isBatch, listingsToCancel, diamondAddress, setSubmitting, writeWithEstimateGas]); + + const buttonText = + cancelCount === 0 ? "No Listings to Cancel" : cancelCount > 1 ? `Cancel ${cancelCount} Listings` : "Cancel Listing"; return ( - <> - - + ); } diff --git a/src/pages/market/actions/CancelOrder.tsx b/src/pages/market/actions/CancelOrder.tsx index 65f80fd86..fa9bfbc99 100644 --- a/src/pages/market/actions/CancelOrder.tsx +++ b/src/pages/market/actions/CancelOrder.tsx @@ -3,28 +3,33 @@ import { TV, TokenValue } from "@/classes/TokenValue"; import FarmBalanceToggle from "@/components/FarmBalanceToggle"; import SmartSubmitButton from "@/components/SmartSubmitButton"; import { Separator } from "@/components/ui/Separator"; +import { ANALYTICS_EVENTS } from "@/constants/analytics-events"; import { PODS } from "@/constants/internalTokens"; import { beanstalkAbi } from "@/generated/contractHooks"; -import { AllPodOrdersQuery } from "@/generated/gql/pintostalk/graphql"; +import { MyPodOrdersQuery } from "@/generated/gql/pintostalk/graphql"; import { useProtocolAddress } from "@/hooks/pinto/useProtocolAddress"; import { useFarmTogglePreference } from "@/hooks/useFarmTogglePreference"; import useTransaction from "@/hooks/useTransaction"; import { useFarmerBalances } from "@/state/useFarmerBalances"; import { useQueryKeys } from "@/state/useQueryKeys"; import useTokenData from "@/state/useTokenData"; +import { trackSimpleEvent } from "@/utils/analytics"; import { formatter } from "@/utils/format"; import { FarmToMode } from "@/utils/types"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import { useAccount } from "wagmi"; +export type MarketplacePodOrder = MyPodOrdersQuery["podOrders"][number]; + export interface CancelOrderProps { - order: AllPodOrdersQuery["podOrders"][number]; + /** Array of orders available for cancellation */ + orders: MarketplacePodOrder[]; } -export default function CancelOrder({ order }: CancelOrderProps) { +export default function CancelOrder({ orders }: CancelOrderProps) { const mainToken = useTokenData().mainToken; const diamondAddress = useProtocolAddress(); const { queryKeys: balanceQKs } = useFarmerBalances(); @@ -42,52 +47,94 @@ export default function CancelOrder({ order }: CancelOrderProps) { [allPodOrders, allMarket, farmerMarket, balanceQKs], ); + const cancelCount = orders.length; + const isBatch = cancelCount > 1; + const onSuccess = useCallback(() => { navigate(`/market/pods/sell`); allQK.forEach((key) => queryClient.invalidateQueries({ queryKey: key })); }, [navigate, queryClient, allQK]); const { writeWithEstimateGas, submitting, isConfirming, setSubmitting } = useTransaction({ - successMessage: "Cancel Order successful", - errorMessage: "Cancel Order failed", + successMessage: isBatch ? `Cancelled ${cancelCount} Orders` : "Cancel Order successful", + errorMessage: isBatch ? "Batch Cancel Orders failed" : "Cancel Order failed", successCallback: onSuccess, }); - const amountOrder = TokenValue.fromBlockchain(order?.beanAmount || 0, mainToken.decimals); - const amountFilled = TokenValue.fromBlockchain(order?.beanAmountFilled || 0, mainToken.decimals); - const remainingBeans = amountOrder.sub(amountFilled); + // Calculate aggregate remaining beans across all orders + const remainingBeans = useMemo(() => { + let total = TokenValue.fromBlockchain(0, mainToken.decimals); + for (const order of orders) { + const amountOrder = TokenValue.fromBlockchain(order?.beanAmount || 0, mainToken.decimals); + const amountFilled = TokenValue.fromBlockchain(order?.beanAmountFilled || 0, mainToken.decimals); + total = total.add(amountOrder.sub(amountFilled)); + } + return total; + }, [orders, mainToken.decimals]); const onSubmit = useCallback(() => { - const maxPlaceInLine = TokenValue.fromBlockchain(order.maxPlaceInLine.toString(), PODS.decimals); - const pricePerPod = TokenValue.fromBlockchain(order.pricePerPod.toString(), mainToken.decimals); - const minFillAmount = TokenValue.fromBlockchain(order.minFillAmount.toString(), PODS.decimals); + if (cancelCount === 0) return; + try { setSubmitting(true); - toast.loading("Cancelling Order..."); + toast.loading(isBatch ? `Cancelling ${cancelCount} Orders...` : "Cancelling Order..."); + + trackSimpleEvent(ANALYTICS_EVENTS.MARKET.POD_ORDER_CANCEL, { + order_count: cancelCount, + is_batch: isBatch, + destination_mode: mode === FarmToMode.INTERNAL ? "farm" : "wallet", + }); + + // Single order: use original cancelPodOrder function + if (!isBatch) { + const order = orders[0]; + const maxPlaceInLine = TokenValue.fromBlockchain(order.maxPlaceInLine.toString(), PODS.decimals); + const pricePerPod = TokenValue.fromBlockchain(order.pricePerPod.toString(), mainToken.decimals); + const minFillAmount = TokenValue.fromBlockchain(order.minFillAmount.toString(), PODS.decimals); + return writeWithEstimateGas({ + address: diamondAddress, + abi: beanstalkAbi, + functionName: "cancelPodOrder", + args: [ + { + orderer: account.address, + fieldId: 0n, + pricePerPod, + maxPlaceInLine, + minFillAmount, + }, + Number(mode), + ], + }); + } + + // Multiple orders: use batchCancelPodOrder + const batchArgs = orders.map((order) => ({ + orderer: account.address, + fieldId: 0n, + pricePerPod: TokenValue.fromBlockchain(order.pricePerPod.toString(), mainToken.decimals), + maxPlaceInLine: TokenValue.fromBlockchain(order.maxPlaceInLine.toString(), PODS.decimals), + minFillAmount: TokenValue.fromBlockchain(order.minFillAmount.toString(), PODS.decimals), + })); + return writeWithEstimateGas({ address: diamondAddress, abi: beanstalkAbi, - functionName: "cancelPodOrder", - args: [ - { - orderer: account.address, // account - fieldId: 0n, // fieldId - pricePerPod, // pricePerPod - maxPlaceInLine, // maxPlaceInLine - minFillAmount, // minFillAmount - }, - Number(mode), // mode - ], + functionName: "batchCancelPodOrder", + args: [batchArgs, Number(mode)], }); } catch (e) { console.error(e); toast.dismiss(); - toast.error("Cancel Order Failed"); + toast.error(isBatch ? "Batch Cancel Orders Failed" : "Cancel Order Failed"); throw e; } finally { setSubmitting(false); } - }, [order, diamondAddress, account, toFarm, mainToken, setSubmitting, writeWithEstimateGas]); + }, [cancelCount, isBatch, orders, diamondAddress, account, mode, mainToken, setSubmitting, writeWithEstimateGas]); + + const buttonText = + cancelCount === 0 ? "No Orders to Cancel" : cancelCount > 1 ? `Cancel ${cancelCount} Orders` : "Cancel Order"; return ( <> @@ -101,9 +148,9 @@ export default function CancelOrder({ order }: CancelOrderProps) { ); diff --git a/src/pages/market/actions/CreateListing.tsx b/src/pages/market/actions/CreateListing.tsx index 5cb237f8f..ee4694e80 100644 --- a/src/pages/market/actions/CreateListing.tsx +++ b/src/pages/market/actions/CreateListing.tsx @@ -29,7 +29,6 @@ import { motion } from "framer-motion"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { toast } from "sonner"; -import { encodeFunctionData } from "viem"; import { useAccount } from "wagmi"; interface LocationState { @@ -543,36 +542,25 @@ export default function CreateListing({ onSelectionChange }: CreateListingProps setSubmitting(true); toast.loading(`Creating ${listingData.length} Listing${listingData.length > 1 ? "s" : ""}...`); - const farmData: `0x${string}`[] = []; - - // Create a listing call for each plot - for (const data of listingData) { - const listingArgs = { - lister: account, - fieldId: 0n, - index: data.index.toBigInt(), - start: data.start.toBigInt(), - podAmount: data.amount.toBigInt(), - pricePerPod: encodedPricePerPod, - maxHarvestableIndex: maxHarvestableIndex.toBigInt(), - minFillAmount: minFill.toBigInt(), - mode: Number(balanceTo), - }; - - const listingCall = encodeFunctionData({ - abi: beanstalkAbi, - functionName: "createPodListing", - args: [listingArgs], - }); - farmData.push(listingCall); - } - - // Use farm to batch all listings in one transaction + // Build batch listing params array + const batchListingArgs = listingData.map((data) => ({ + lister: account, + fieldId: 0n, + index: data.index.toBigInt(), + start: data.start.toBigInt(), + podAmount: data.amount.toBigInt(), + pricePerPod: encodedPricePerPod, + maxHarvestableIndex: maxHarvestableIndex.toBigInt(), + minFillAmount: minFill.toBigInt(), + mode: Number(balanceTo), + })); + + // Use native batchCreatePodListing for gas-efficient batch creation writeWithEstimateGas({ address: diamondAddress, abi: beanstalkAbi, - functionName: "farm", - args: [farmData], + functionName: "batchCreatePodListing", + args: [batchListingArgs], }); } catch (e: unknown) { console.error(e); diff --git a/src/pages/market/actions/FillListing.tsx b/src/pages/market/actions/FillListing.tsx index b00a9239f..d4e308beb 100644 --- a/src/pages/market/actions/FillListing.tsx +++ b/src/pages/market/actions/FillListing.tsx @@ -45,7 +45,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import { toast } from "sonner"; -import { Address, encodeFunctionData } from "viem"; +import { Address } from "viem"; import { useAccount } from "wagmi"; // Configuration constants @@ -560,47 +560,37 @@ export default function FillListing({ selectedListingId, selectedPlaceInLine, on toast.loading(`Filling ${listingsToFill.length} Listing${listingsToFill.length !== 1 ? "s" : ""}...`); if (isUsingMain) { - // Direct fill - create farm calls for each listing - const farmData: `0x${string}`[] = []; - - for (const { listing, beanAmount } of listingsToFill) { - // Encode pricePerPod with 6 decimals (like CreateOrder.tsx) + // Direct fill - use batchFillPodListing for gas-efficient batching + const batchFillArgs = listingsToFill.map(({ listing, beanAmount }) => { const pricePerPodNumber = TokenValue.fromBlockchain(listing.pricePerPod, mainToken.decimals).toNumber(); const encodedPricePerPod = Math.floor(pricePerPodNumber * PRICE_PER_POD_CONFIG.DECIMAL_MULTIPLIER); - const fillCall = encodeFunctionData({ - abi: beanstalkAbi, - functionName: "fillPodListing", - args: [ - { - lister: listing.farmer.id as Address, - fieldId: 0n, - index: TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt(), - start: TokenValue.fromBlockchain(listing.start, PODS.decimals).toBigInt(), - podAmount: TokenValue.fromBlockchain(listing.amount, PODS.decimals).toBigInt(), - pricePerPod: encodedPricePerPod, - maxHarvestableIndex: TokenValue.fromBlockchain(listing.maxHarvestableIndex, PODS.decimals).toBigInt(), - minFillAmount: TokenValue.fromBlockchain(listing.minFillAmount, mainToken.decimals).toBigInt(), - mode: Number(listing.mode), - }, - beanAmount.toBigInt(), - Number(balanceFrom), - ], - }); - - farmData.push(fillCall); - } + return { + podListing: { + lister: listing.farmer.id as Address, + fieldId: 0n, + index: TokenValue.fromBlockchain(listing.index, PODS.decimals).toBigInt(), + start: TokenValue.fromBlockchain(listing.start, PODS.decimals).toBigInt(), + podAmount: TokenValue.fromBlockchain(listing.amount, PODS.decimals).toBigInt(), + pricePerPod: encodedPricePerPod, + maxHarvestableIndex: TokenValue.fromBlockchain(listing.maxHarvestableIndex, PODS.decimals).toBigInt(), + minFillAmount: TokenValue.fromBlockchain(listing.minFillAmount, mainToken.decimals).toBigInt(), + mode: Number(listing.mode), + }, + beanAmount: beanAmount.toBigInt(), + mode: Number(balanceFrom), + }; + }); - if (farmData.length === 0) { + if (batchFillArgs.length === 0) { throw new Error("No valid fill operations to execute"); } - // Use farm to batch all listing fills in one transaction return writeWithEstimateGas({ address: diamondAddress, abi: beanstalkAbi, - functionName: "farm", - args: [farmData], + functionName: "batchFillPodListing", + args: [batchFillArgs], }); } else if (swapBuild?.advancedFarm.length) { // Swap + fill - use advancedFarm diff --git a/src/pages/market/actions/FillOrder.tsx b/src/pages/market/actions/FillOrder.tsx index a75aa2af9..e515605f9 100644 --- a/src/pages/market/actions/FillOrder.tsx +++ b/src/pages/market/actions/FillOrder.tsx @@ -27,7 +27,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import { toast } from "sonner"; -import { Address, encodeFunctionData } from "viem"; +import { Address } from "viem"; import { useAccount } from "wagmi"; import CancelOrder from "./CancelOrder"; @@ -336,7 +336,19 @@ export default function FillOrder({ selectedOrderId }: FillOrderProps) { let currentPlot = sortedPlots[0]; let currentPlotStartOffset = 0; - const farmData: `0x${string}`[] = []; + const batchFillArgs: { + podOrder: { + orderer: Address; + fieldId: bigint; + pricePerPod: number; + maxPlaceInLine: bigint; + minFillAmount: bigint; + }; + index: bigint; + start: bigint; + amount: bigint; + mode: number; + }[] = []; for (const { order: orderToFill, amount: fillAmount } of ordersToFill) { let remainingAmount = fillAmount; @@ -370,29 +382,20 @@ export default function FillOrder({ selectedOrderId }: FillOrderProps) { const podAmount = TokenValue.fromHuman(podsToUse, PODS.decimals); const startOffset = TokenValue.fromHuman(currentPlotStartOffset, PODS.decimals); - // Create fillPodOrder call for this order with pod allocation from current plot - const fillOrderArgs = { - orderer: orderToFill.farmer.id as Address, - fieldId: FIELD_ID, - maxPlaceInLine: BigInt(orderToFill.maxPlaceInLine), - pricePerPod: Number(orderToFill.pricePerPod), - minFillAmount: BigInt(orderToFill.minFillAmount), - }; - - const fillCall = encodeFunctionData({ - abi: beanstalkAbi, - functionName: "fillPodOrder", - args: [ - fillOrderArgs, - currentPlot.index.toBigInt(), - startOffset.toBigInt(), - podAmount.toBigInt(), - Number(FarmToMode.INTERNAL), - ], + batchFillArgs.push({ + podOrder: { + orderer: orderToFill.farmer.id as Address, + fieldId: FIELD_ID, + pricePerPod: Number(orderToFill.pricePerPod), + maxPlaceInLine: BigInt(orderToFill.maxPlaceInLine), + minFillAmount: BigInt(orderToFill.minFillAmount), + }, + index: currentPlot.index.toBigInt(), + start: startOffset.toBigInt(), + amount: podAmount.toBigInt(), + mode: Number(FarmToMode.INTERNAL), }); - farmData.push(fillCall); - // Update tracking variables remainingAmount -= podsToUse; remainingPodsInCurrentPlot -= podsToUse; @@ -407,17 +410,17 @@ export default function FillOrder({ selectedOrderId }: FillOrderProps) { } } - if (farmData.length === 0) { + if (batchFillArgs.length === 0) { throw new Error("No valid fill operations to execute"); } - // Use farm to batch all order fills in one transaction + // Use batchFillPodOrder for gas-efficient batching // Success state will be set in onSuccess callback via ref writeWithEstimateGas({ address: diamondAddress, abi: beanstalkAbi, - functionName: "farm", - args: [farmData], + functionName: "batchFillPodOrder", + args: [batchFillArgs], }); } catch (e) { console.error("Fill order error:", e); @@ -509,11 +512,7 @@ export default function FillOrder({ selectedOrderId }: FillOrderProps) { {isOwnOrder && selectedOrders.length > 0 && ( <> - {selectedOrders - .filter((order) => order.farmer.id === account.address?.toLowerCase()) - .map((order) => ( - - ))} + order.farmer.id === account.address?.toLowerCase())} /> )} diff --git a/src/queries/beanstalk/podmarket/MyPodListings.graphql b/src/queries/beanstalk/podmarket/MyPodListings.graphql new file mode 100644 index 000000000..1777f23ee --- /dev/null +++ b/src/queries/beanstalk/podmarket/MyPodListings.graphql @@ -0,0 +1,23 @@ +#import "./PodListing.fragment.graphql" + +query MyPodListings( + $first: Int = 100 + $skip: Int = 0 + $account: String! + $maxHarvestableIndex: BigInt! +) { + podListings( + first: $first + skip: $skip + where: { + farmer: $account + status: ACTIVE + maxHarvestableIndex_gt: $maxHarvestableIndex + remainingAmount_gt: "100000" # = 0.10 Pods. hides dust pods. + } + orderBy: createdAt + orderDirection: desc + ) { + ...PodListing + } +} diff --git a/src/queries/beanstalk/podmarket/MyPodOrders.graphql b/src/queries/beanstalk/podmarket/MyPodOrders.graphql new file mode 100644 index 000000000..236567b71 --- /dev/null +++ b/src/queries/beanstalk/podmarket/MyPodOrders.graphql @@ -0,0 +1,20 @@ +#import "./PodOrder.fragment.graphql" + +query MyPodOrders( + $first: Int = 100 + $skip: Int = 0 + $account: String! +) { + podOrders( + first: $first + skip: $skip + where: { + farmer: $account + status: ACTIVE + } + orderBy: createdAt + orderDirection: desc + ) { + ...PodOrder + } +} diff --git a/src/state/market/useMyPodListings.ts b/src/state/market/useMyPodListings.ts new file mode 100644 index 000000000..d3a26a631 --- /dev/null +++ b/src/state/market/useMyPodListings.ts @@ -0,0 +1,47 @@ +import { subgraphs } from "@/constants/subgraph"; +import { MyPodListingsDocument } from "@/generated/gql/pintostalk/graphql"; +import { useQuery } from "@tanstack/react-query"; +import request from "graphql-request"; +import { useMemo } from "react"; +import { useChainId } from "wagmi"; +import { useHarvestableIndex } from "../useFieldData"; + +export interface UseMyPodListingsProps { + /** Connected wallet address to filter listings by */ + account: string | undefined; +} + +/** + * Fetches pod listings owned by the specified account. + * Returns only active, non-expired listings with remaining amount > 0.10 pods. + */ +export default function useMyPodListings({ account }: UseMyPodListingsProps) { + const chainId = useChainId(); + const harvestableIndex = useHarvestableIndex(); + + const queryKey = useMemo( + () => ["myPodListings", { chainId, account: account?.toLowerCase(), harvestableIndex: harvestableIndex.toHuman() }], + [chainId, account, harvestableIndex], + ); + + const query = useQuery({ + queryKey, + queryFn: async () => + request(subgraphs[chainId].beanstalk, MyPodListingsDocument, { + account: account?.toLowerCase(), + maxHarvestableIndex: harvestableIndex.toBigInt().toString(), + first: 100, + skip: 0, + }), + enabled: !!account && harvestableIndex.gt(0), + }); + + return { + data: query.data, + listings: query.data?.podListings, + isLoading: query.isLoading, + isFetching: query.isFetching, + isLoaded: !!query.data, + queryKey, + }; +} diff --git a/src/state/market/useMyPodOrders.ts b/src/state/market/useMyPodOrders.ts new file mode 100644 index 000000000..1335928a8 --- /dev/null +++ b/src/state/market/useMyPodOrders.ts @@ -0,0 +1,41 @@ +import { subgraphs } from "@/constants/subgraph"; +import { MyPodOrdersDocument } from "@/generated/gql/pintostalk/graphql"; +import { useQuery } from "@tanstack/react-query"; +import request from "graphql-request"; +import { useMemo } from "react"; +import { useChainId } from "wagmi"; + +export interface UseMyPodOrdersProps { + /** Connected wallet address to filter orders by */ + account: string | undefined; +} + +/** + * Fetches pod orders owned by the specified account. + * Returns only active orders. + */ +export default function useMyPodOrders({ account }: UseMyPodOrdersProps) { + const chainId = useChainId(); + + const queryKey = useMemo(() => ["myPodOrders", { chainId, account: account?.toLowerCase() }], [chainId, account]); + + const query = useQuery({ + queryKey, + queryFn: async () => + request(subgraphs[chainId].beanstalk, MyPodOrdersDocument, { + account: account?.toLowerCase(), + first: 100, + skip: 0, + }), + enabled: !!account, + }); + + return { + data: query.data, + orders: query.data?.podOrders, + isLoading: query.isLoading, + isFetching: query.isFetching, + isLoaded: !!query.data, + queryKey, + }; +}