From a53c3a527d4efec23d3146eb4272152f1e87e7d4 Mon Sep 17 00:00:00 2001 From: mmackz Date: Tue, 9 Jul 2024 22:01:56 -0700 Subject: [PATCH 1/2] fix(fabric): fix amount zero issue --- packages/fabric/src/Fabric.test.ts | 17 ++++--- packages/fabric/src/Fabric.ts | 76 +++++++++++++++++++++++------- packages/fabric/src/abi.ts | 35 +++++++------- packages/fabric/src/utils.ts | 10 ++-- 4 files changed, 94 insertions(+), 44 deletions(-) diff --git a/packages/fabric/src/Fabric.test.ts b/packages/fabric/src/Fabric.test.ts index 2fb37f54e..7e650aa66 100644 --- a/packages/fabric/src/Fabric.test.ts +++ b/packages/fabric/src/Fabric.test.ts @@ -4,7 +4,7 @@ import { Chains, type MintIntentParams, } from '@rabbitholegg/questdk-plugin-utils' -import { apply } from '@rabbitholegg/questdk/filter' +import { apply } from '@rabbitholegg/questdk' import { type Address } from 'viem' import { describe, expect, test } from 'vitest' @@ -13,11 +13,11 @@ describe('Given the fabric plugin', () => { describe('should return a valid action filter', () => { test('when making a valid mint action', async () => { const filter = await mint({ - chainId: 1, - contractAddress: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + chainId: 8453, + contractAddress: '0x2efc6064239121d1d7efb503355daa82b87ee89c', }) expect(filter).toBeTypeOf('object') - expect(Number(filter.chainId)).toBe(1) + expect(Number(filter.chainId)).toBe(8453) if (typeof filter.to === 'string') { expect(filter.to).toMatch(/^0x[a-fA-F0-9]{40}$/) } else { @@ -57,8 +57,13 @@ describe('Given the fabric plugin', () => { failingTestCases.forEach((testCase) => { const { transaction, description, params } = testCase test(description, async () => { - const filter = await mint(params) - expect(apply(transaction, filter)).to.be.false + try { + const filter = await mint(params) + const result = apply(transaction, filter) + expect(result).toBe(false) + } catch (error) { + expect(error).toBeInstanceOf(Error) + } }) }) }) diff --git a/packages/fabric/src/Fabric.ts b/packages/fabric/src/Fabric.ts index b65d1d077..b44b1187f 100644 --- a/packages/fabric/src/Fabric.ts +++ b/packages/fabric/src/Fabric.ts @@ -1,13 +1,16 @@ -import { FABRIC_ABI } from './abi' +import { FABRIC_MINT_ABI, FABRIC_MINTFOR_ABI } from './abi' import { getContractData } from './utils' import { type MintActionParams, type TransactionFilter, compressJson, + GreaterThanOrEqual, } from '@rabbitholegg/questdk' import { Chains, DEFAULT_ACCOUNT, + chainIdToViemChain, + getMintAmount, type MintIntentParams, } from '@rabbitholegg/questdk-plugin-utils' import { @@ -15,20 +18,43 @@ import { type PublicClient, type SimulateContractReturnType, type TransactionRequest, + createPublicClient, encodeFunctionData, + http, zeroAddress, } from 'viem' export const mint = async ( mint: MintActionParams, ): Promise => { - const { chainId, contractAddress, recipient } = mint + const { chainId, contractAddress, amount, recipient } = mint + + const { minPurchaseSeconds, tps } = await getContractData( + chainId, + contractAddress, + ) + + if (minPurchaseSeconds == null || tps == null) { + throw new Error('Contract data not found') + } + + const numTokens = minPurchaseSeconds * tps * getMintAmount(amount) + return compressJson({ chainId, to: contractAddress, input: { - $abi: FABRIC_ABI, - account: recipient, + $or: [ + { + $abi: FABRIC_MINT_ABI, + numTokens: GreaterThanOrEqual(numTokens), + }, + { + $abi: FABRIC_MINTFOR_ABI, + numTokens: GreaterThanOrEqual(numTokens), + account: recipient, + }, + ], }, }) } @@ -54,9 +80,13 @@ export const getFees = async ( throw new Error('ERC20 not supported') } - const mintUnits = typeof amount === 'number' ? BigInt(amount) : BigInt(1) + if (!minPurchaseSeconds || !tps) { + throw new Error('Contract data not found') + } + + const mintUnits = getMintAmount(amount) - const mintCost = (minPurchaseSeconds as bigint) * (tps as bigint) * mintUnits + const mintCost = minPurchaseSeconds * tps * mintUnits return { actionFee: mintCost, projectFee: BigInt(0) } } @@ -75,10 +105,14 @@ export const getMintIntent = async ( throw new Error('ERC20 not supported') } - const mintArgs = [(minPurchaseSeconds as bigint) * (tps as bigint) * amount] + if (!minPurchaseSeconds || !tps) { + throw new Error('Contract data not found') + } + + const mintArgs = [minPurchaseSeconds * tps * getMintAmount(amount)] const data = encodeFunctionData({ - abi: FABRIC_ABI, + abi: FABRIC_MINT_ABI, functionName: 'mint', args: mintArgs, }) @@ -98,25 +132,35 @@ export const simulateMint = async ( ): Promise => { const { chainId, contractAddress, amount } = mint + const _client = + client ?? + createPublicClient({ + chain: chainIdToViemChain(chainId), + transport: http(), + }) + const from = account ?? DEFAULT_ACCOUNT - const { - erc20Address, - minPurchaseSeconds, - tps, - client: _client, - } = await getContractData(chainId, contractAddress, client) + const { erc20Address, minPurchaseSeconds, tps } = await getContractData( + chainId, + contractAddress, + client, + ) // fail simulation if erc20 is used if (erc20Address !== zeroAddress) { throw new Error('ERC20 not supported') } - const mintArgs = [(minPurchaseSeconds as bigint) * (tps as bigint) * amount] + if (!minPurchaseSeconds || !tps) { + throw new Error('Contract data not found') + } + + const mintArgs = [minPurchaseSeconds * tps * getMintAmount(amount)] const result = await _client.simulateContract({ address: contractAddress, value, - abi: FABRIC_ABI, + abi: FABRIC_MINT_ABI, functionName: 'mint', args: mintArgs, account: from, diff --git a/packages/fabric/src/abi.ts b/packages/fabric/src/abi.ts index 2a203a7f9..29ce20a57 100644 --- a/packages/fabric/src/abi.ts +++ b/packages/fabric/src/abi.ts @@ -1,4 +1,4 @@ -export const FABRIC_ABI = [ +export const FABRIC_MINT_ABI = [ { inputs: [ { @@ -15,40 +15,43 @@ export const FABRIC_ABI = [ { inputs: [ { - internalType: 'address', - name: 'account', - type: 'address', + internalType: 'uint256', + name: 'numTokens', + type: 'uint256', }, { internalType: 'uint256', - name: 'numTokens', + name: 'referralCode', type: 'uint256', }, + { + internalType: 'address', + name: 'referrer', + type: 'address', + }, ], - name: 'mintFor', + name: 'mintWithReferral', outputs: [], stateMutability: 'payable', type: 'function', }, +] + +export const FABRIC_MINTFOR_ABI = [ { inputs: [ { - internalType: 'uint256', - name: 'numTokens', - type: 'uint256', + internalType: 'address', + name: 'account', + type: 'address', }, { internalType: 'uint256', - name: 'referralCode', + name: 'numTokens', type: 'uint256', }, - { - internalType: 'address', - name: 'referrer', - type: 'address', - }, ], - name: 'mintWithReferral', + name: 'mintFor', outputs: [], stateMutability: 'payable', type: 'function', diff --git a/packages/fabric/src/utils.ts b/packages/fabric/src/utils.ts index a81e3bb98..15276d450 100644 --- a/packages/fabric/src/utils.ts +++ b/packages/fabric/src/utils.ts @@ -4,9 +4,8 @@ import { type Address, type PublicClient, createPublicClient, http } from 'viem' interface ContractData { erc20Address: Address - minPurchaseSeconds: bigint - tps: bigint - client: PublicClient + minPurchaseSeconds: bigint | undefined + tps: bigint | undefined } export async function getContractData( @@ -38,8 +37,7 @@ export async function getContractData( return { erc20Address: erc20Address as Address, - minPurchaseSeconds: minPurchaseSeconds as bigint, - tps: tps as bigint, - client: client as PublicClient, + minPurchaseSeconds: minPurchaseSeconds as bigint | undefined, + tps: tps as bigint | undefined, } } From a373fdecb7e7f1ca91e79b95f8b40d82306bfe35 Mon Sep 17 00:00:00 2001 From: mmackz Date: Tue, 9 Jul 2024 22:02:18 -0700 Subject: [PATCH 2/2] chore: generate changeset --- .changeset/short-roses-pull.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/short-roses-pull.md diff --git a/.changeset/short-roses-pull.md b/.changeset/short-roses-pull.md new file mode 100644 index 000000000..949de81db --- /dev/null +++ b/.changeset/short-roses-pull.md @@ -0,0 +1,5 @@ +--- +"@rabbitholegg/questdk-plugin-fabric": minor +--- + +fix amount zero issue