From d7593d93fafae333508ef6cf012adc2ee7f712fa Mon Sep 17 00:00:00 2001 From: Cesare Naldi Date: Thu, 16 May 2024 18:46:52 +0200 Subject: [PATCH] Verify allowance and balance of mint fee token too --- .../web/src/publications/UseOpenAction.tsx | 2 +- .../src/use-cases/publications/OpenAction.ts | 22 +++++++---- .../publications/__helpers__/mocks.ts | 16 ++++++-- .../publications/__tests__/OpenAction.spec.ts | 39 +++++++++++++++---- .../adapters/OpenActionGateway.ts | 13 ++----- .../__tests__/OpenActionGateway.spec.ts | 7 ++-- .../adapters/schemas/publications.ts | 15 ++++--- .../useOpenAction/createOpenActionRequest.ts | 16 +++++--- 8 files changed, 88 insertions(+), 42 deletions(-) diff --git a/examples/web/src/publications/UseOpenAction.tsx b/examples/web/src/publications/UseOpenAction.tsx index 2b4e779dc..4fb0b477e 100644 --- a/examples/web/src/publications/UseOpenAction.tsx +++ b/examples/web/src/publications/UseOpenAction.tsx @@ -117,7 +117,7 @@ export function UseOpenAction() { metadata: uri, actions: [ { - type: OpenActionType.SIMPLE_COLLECT, + type: OpenActionType.SHARED_REVENUE_COLLECT, followerOnly: false, collectLimit: 5, }, diff --git a/packages/domain/src/use-cases/publications/OpenAction.ts b/packages/domain/src/use-cases/publications/OpenAction.ts index c83cfd2ae..8ae20187f 100644 --- a/packages/domain/src/use-cases/publications/OpenAction.ts +++ b/packages/domain/src/use-cases/publications/OpenAction.ts @@ -27,13 +27,21 @@ export enum AllOpenActionType { UNKNOWN_OPEN_ACTION = 'UNKNOWN_OPEN_ACTION', } +export enum FeeType { + COLLECT = 'COLLECT', + MINT = 'MINT', +} + export type CollectFee = { + type: FeeType.COLLECT; amount: Amount; contractAddress: EvmAddress; }; -export type SharedMintFee = { +export type MintFee = { + type: FeeType.MINT; amount: Amount; + contractAddress: EvmAddress; executorClient?: EvmAddress; }; @@ -54,7 +62,6 @@ export type MultirecipientCollectRequest = { publicationId: PublicationId; referrers?: Referrers; fee: CollectFee; - collectModule: EvmAddress; public: boolean; signless: boolean; sponsored: boolean; @@ -66,7 +73,6 @@ export type SimpleCollectRequest = { publicationId: PublicationId; referrers?: Referrers; fee?: CollectFee; - collectModule: EvmAddress; public: boolean; signless: boolean; sponsored: boolean; @@ -77,10 +83,7 @@ export type SharedRevenueCollectRequest = { type: AllOpenActionType.SHARED_REVENUE_COLLECT; publicationId: PublicationId; referrers?: Referrers; - fee?: CollectFee; - mintFee?: SharedMintFee; - executorClient?: EvmAddress; - collectModule: EvmAddress; + fee: CollectFee | MintFee; public: boolean; signless: boolean; sponsored: boolean; @@ -127,8 +130,11 @@ export function isUnknownActionRequest( return request.type === AllOpenActionType.UNKNOWN_OPEN_ACTION; } -export type PaidCollectRequest = CollectRequest & { fee: CollectFee }; +type PaidCollectRequest = CollectRequest & { fee: CollectFee | MintFee }; +/** + * @internal + */ export function isPaidCollectRequest(request: OpenActionRequest): request is PaidCollectRequest { return isCollectRequest(request) && 'fee' in request && request.fee !== undefined; } diff --git a/packages/domain/src/use-cases/publications/__helpers__/mocks.ts b/packages/domain/src/use-cases/publications/__helpers__/mocks.ts index 14763c3c4..d9a227ca5 100644 --- a/packages/domain/src/use-cases/publications/__helpers__/mocks.ts +++ b/packages/domain/src/use-cases/publications/__helpers__/mocks.ts @@ -12,7 +12,9 @@ import { HidePublicationRequest } from '../HidePublication'; import { AllOpenActionType, CollectFee, + FeeType, LegacyCollectRequest, + MintFee, MultirecipientCollectRequest, SharedRevenueCollectRequest, SimpleCollectRequest, @@ -133,6 +135,16 @@ export function mockCollectFee(overrides?: Partial): CollectFee { amount: mockDaiAmount(1, ChainType.POLYGON), contractAddress: mockEvmAddress(), ...overrides, + type: FeeType.COLLECT, + }; +} + +export function mockMintFee(overrides?: Partial): MintFee { + return { + amount: mockDaiAmount(1, ChainType.POLYGON), + contractAddress: mockEvmAddress(), + ...overrides, + type: FeeType.MINT, }; } @@ -155,10 +167,10 @@ export function mockSharedRevenueCollectRequest( ): SharedRevenueCollectRequest { return { publicationId: mockPublicationId(), + fee: mockMintFee(), public: false, signless: true, sponsored: true, - collectModule: mockEvmAddress(), ...overrides, type: AllOpenActionType.SHARED_REVENUE_COLLECT, kind: TransactionKind.ACT_ON_PUBLICATION, @@ -173,7 +185,6 @@ export function mockSimpleCollectRequest( public: false, signless: true, sponsored: true, - collectModule: mockEvmAddress(), ...overrides, type: AllOpenActionType.SIMPLE_COLLECT, kind: TransactionKind.ACT_ON_PUBLICATION, @@ -189,7 +200,6 @@ export function mockMultirecipientCollectRequest( public: false, signless: true, sponsored: true, - collectModule: mockEvmAddress(), ...overrides, type: AllOpenActionType.MULTIRECIPIENT_COLLECT, kind: TransactionKind.ACT_ON_PUBLICATION, diff --git a/packages/domain/src/use-cases/publications/__tests__/OpenAction.spec.ts b/packages/domain/src/use-cases/publications/__tests__/OpenAction.spec.ts index c716aa05b..34108fee9 100644 --- a/packages/domain/src/use-cases/publications/__tests__/OpenAction.spec.ts +++ b/packages/domain/src/use-cases/publications/__tests__/OpenAction.spec.ts @@ -21,7 +21,9 @@ import { import { mockCollectFee, mockLegacyCollectRequest, + mockMintFee, mockMultirecipientCollectRequest, + mockSharedRevenueCollectRequest, mockSimpleCollectRequest, mockUnknownActionRequest, } from '../__helpers__/mocks'; @@ -54,7 +56,7 @@ function setupOpenAction({ } describe(`Given the ${OpenAction.name} use-case interactor`, () => { - describe.only.each([ + describe.each([ { description: 'LegacyCollectRequest', request: mockLegacyCollectRequest({ fee: mockCollectFee() }), @@ -63,6 +65,14 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { description: 'SimpleCollectRequest', request: mockSimpleCollectRequest({ fee: mockCollectFee() }), }, + { + description: 'SharedRevenueCollectRequest with mint fee', + request: mockSharedRevenueCollectRequest({ fee: mockMintFee() }), + }, + { + description: 'SharedRevenueCollectRequest with collect fee', + request: mockSharedRevenueCollectRequest({ fee: mockCollectFee() }), + }, { description: 'MultirecipientCollectRequest', request: mockMultirecipientCollectRequest(), @@ -75,7 +85,7 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { description: 'public MultirecipientCollectRequest', request: mockMultirecipientCollectRequest({ public: true }), }, - ])(`when executed with a request that requires a fee`, ({ request, description }) => { + ])(`when executed with a request that involves a fee`, ({ request, description }) => { invariant(isPaidCollectRequest(request), 'Test misconfiguration.'); it(`should check the token availability for ${description}`, async () => { @@ -104,7 +114,7 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { }); }); - describe.only.each([ + describe.each([ { type: 'LegacyCollectRequest', request: mockLegacyCollectRequest({ fee: mockCollectFee() }), @@ -113,11 +123,15 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { type: 'SimpleCollectRequest', request: mockSimpleCollectRequest({ fee: mockCollectFee() }), }, + { + type: 'SharedRevenueCollectRequest with mint fee', + request: mockSharedRevenueCollectRequest(), + }, { type: 'MultirecipientCollectRequest', request: mockMultirecipientCollectRequest(), }, - ])(`when executed with a request that requires a fee`, ({ request, type }) => { + ])(`when executed with a request that involves a fee`, ({ request, type }) => { invariant(isPaidCollectRequest(request), 'Test misconfiguration.'); it(`should support the ${SignedOnChain.name}<${type}> strategy`, async () => { @@ -140,12 +154,17 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { }); }); - describe.only.each([ + describe.each([ { type: 'SimpleCollectRequest', request: mockSimpleCollectRequest({ fee: undefined, public: true }), tokenAvailability: mock(), }, + { + type: 'SharedRevenueCollectRequest', + request: mockSharedRevenueCollectRequest({ public: true }), + tokenAvailability: mockTokeAvailability({ result: success() }), + }, { type: 'UnknownActionRequest', request: mockUnknownActionRequest({ public: true }), @@ -170,7 +189,7 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { }); }); - describe.only.each([ + describe.each([ { type: 'LegacyCollectRequest', request: mockLegacyCollectRequest({ fee: undefined }), @@ -184,7 +203,7 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { request: mockUnknownActionRequest(), }, ])( - `when executed with a request without fee or for which is not possible to determine (e.g. unknown open action)`, + `when executed with a request without fee or for which is not possible to determine if requires a fee (e.g. unknown open action)`, ({ request, type }) => { it(`should support the ${DelegableSigning.name}<${type}> strategy`, async () => { const { openAction, signedExecution, delegableExecution, paidExecution } = @@ -199,7 +218,7 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { }, ); - describe.only.each([ + describe.each([ { type: 'LegacyCollectRequest', request: mockLegacyCollectRequest({ sponsored: false }), @@ -208,6 +227,10 @@ describe(`Given the ${OpenAction.name} use-case interactor`, () => { type: 'SimpleCollectRequest', request: mockSimpleCollectRequest({ sponsored: false }), }, + { + type: 'SharedRevenueCollectRequest', + request: mockSharedRevenueCollectRequest({ sponsored: false }), + }, { type: 'UnknownActionRequest', request: mockUnknownActionRequest({ sponsored: false }), diff --git a/packages/react/src/transactions/adapters/OpenActionGateway.ts b/packages/react/src/transactions/adapters/OpenActionGateway.ts index ac65420d1..6334035bb 100644 --- a/packages/react/src/transactions/adapters/OpenActionGateway.ts +++ b/packages/react/src/transactions/adapters/OpenActionGateway.ts @@ -15,6 +15,7 @@ import { NativeTransaction, Nonce } from '@lens-protocol/domain/entities'; import { AllOpenActionType, DelegableOpenActionRequest, + FeeType, LegacyCollectRequest, OpenActionRequest, isUnknownActionRequest, @@ -206,7 +207,7 @@ export class OpenActionGateway for: request.publicationId, actOn: { protocolSharedRevenueCollectOpenAction: { - executorClient: request.executorClient ?? null, + executorClient: request.fee.type === FeeType.MINT ? request.fee.executorClient : null, }, }, referrers: resolveOnchainReferrers(request.referrers), @@ -379,6 +380,7 @@ export class OpenActionGateway private resolvePublicPaidActAmount(request: NewOpenActionRequest): Erc20Amount { switch (request.type) { case AllOpenActionType.MULTIRECIPIENT_COLLECT: + case AllOpenActionType.SHARED_REVENUE_COLLECT: return request.fee.amount; case AllOpenActionType.UNKNOWN_OPEN_ACTION: @@ -387,13 +389,6 @@ export class OpenActionGateway case AllOpenActionType.SIMPLE_COLLECT: return request.fee?.amount ?? never(); - case AllOpenActionType.SHARED_REVENUE_COLLECT: - return ( - request.fee?.amount ?? - request.mintFee?.amount ?? - never('Invalid UnknownActionRequest, missing fee and mintFee') - ); - default: never(); } @@ -417,7 +412,7 @@ export class OpenActionGateway }, amount.asset.address, amount.toBigDecimal().toHexadecimal(), - isUnknownActionRequest(request) ? contract.address : request.collectModule, + isUnknownActionRequest(request) ? contract.address : request.fee?.contractAddress ?? never(), ]); return { contractAddress: result.typedData.domain.verifyingContract, diff --git a/packages/react/src/transactions/adapters/__tests__/OpenActionGateway.spec.ts b/packages/react/src/transactions/adapters/__tests__/OpenActionGateway.spec.ts index 700c822ec..52bc9a048 100644 --- a/packages/react/src/transactions/adapters/__tests__/OpenActionGateway.spec.ts +++ b/packages/react/src/transactions/adapters/__tests__/OpenActionGateway.spec.ts @@ -18,8 +18,8 @@ import { } from '@lens-protocol/api-bindings/mocks'; import { NativeTransaction, UnsignedTransaction } from '@lens-protocol/domain/entities'; import { - mockCollectFee, mockLegacyCollectRequest, + mockMintFee, mockMultirecipientCollectRequest, mockNonce, mockProfileId, @@ -500,8 +500,9 @@ describe(`Given an instance of ${OpenActionGateway.name}`, () => { publicationId, referrers, public: true, - fee: mockCollectFee(), - executorClient: '0xAbAe21DD8737DbdCa26A16D6210D9293986800f9', + fee: mockMintFee({ + executorClient: '0xAbAe21DD8737DbdCa26A16D6210D9293986800f9', + }), }), expectedRequest: { for: publicationId, diff --git a/packages/react/src/transactions/adapters/schemas/publications.ts b/packages/react/src/transactions/adapters/schemas/publications.ts index f78e26506..484fbf217 100644 --- a/packages/react/src/transactions/adapters/schemas/publications.ts +++ b/packages/react/src/transactions/adapters/schemas/publications.ts @@ -10,6 +10,7 @@ import { RecipientWithSplit, ReferencePolicyType, OpenActionRequest, + FeeType, } from '@lens-protocol/domain/use-cases/publications'; import { UnknownObject } from '@lens-protocol/shared-kernel'; import { z } from 'zod'; @@ -177,10 +178,18 @@ export const CreateMirrorRequestSchema: z.ZodType< }); const CollectFeeSchema = z.object({ + type: z.literal(FeeType.COLLECT), amount: Erc20AmountSchema, contractAddress: EvmAddressSchema, }); +const MintFeeSchema = z.object({ + type: z.literal(FeeType.MINT), + amount: Erc20AmountSchema, + contractAddress: EvmAddressSchema, + executorClient: EvmAddressSchema.optional(), +}); + const BaseCollectRequestSchema = z.object({ kind: z.literal(TransactionKind.ACT_ON_PUBLICATION), publicationId: PublicationIdSchema, @@ -201,7 +210,6 @@ export const SimpleCollectRequestSchema = BaseCollectRequestSchema.extend({ publicationId: PublicationIdSchema, referrers: ReferrersSchema.optional(), fee: CollectFeeSchema.optional(), - collectModule: EvmAddressSchema, public: z.boolean(), signless: z.boolean(), sponsored: z.boolean(), @@ -211,12 +219,10 @@ export const SharedRevenueCollectRequestSchema = BaseCollectRequestSchema.extend type: z.literal(AllOpenActionType.SHARED_REVENUE_COLLECT), publicationId: PublicationIdSchema, referrers: ReferrersSchema.optional(), - fee: CollectFeeSchema.optional(), - collectModule: EvmAddressSchema, + fee: z.discriminatedUnion('type', [CollectFeeSchema, MintFeeSchema]), public: z.boolean(), signless: z.boolean(), sponsored: z.boolean(), - executorClient: EvmAddressSchema.optional(), }); export const MultirecipientCollectRequestSchema = BaseCollectRequestSchema.extend({ @@ -224,7 +230,6 @@ export const MultirecipientCollectRequestSchema = BaseCollectRequestSchema.exten publicationId: PublicationIdSchema, referrers: ReferrersSchema.optional(), fee: CollectFeeSchema, - collectModule: EvmAddressSchema, public: z.boolean(), signless: z.boolean(), sponsored: z.boolean(), diff --git a/packages/react/src/transactions/useOpenAction/createOpenActionRequest.ts b/packages/react/src/transactions/useOpenAction/createOpenActionRequest.ts index 5027458e0..89ff76eb8 100644 --- a/packages/react/src/transactions/useOpenAction/createOpenActionRequest.ts +++ b/packages/react/src/transactions/useOpenAction/createOpenActionRequest.ts @@ -9,6 +9,7 @@ import { TransactionKind } from '@lens-protocol/domain/entities'; import { AllOpenActionType, CollectRequest, + FeeType, OpenActionRequest, UnknownActionRequest, } from '@lens-protocol/domain/use-cases/publications'; @@ -63,6 +64,7 @@ function resolveCollectRequestFor( publicationId: collectable.id, referrer: args.publication !== collectable ? args.publication.id : undefined, fee: { + type: FeeType.COLLECT, amount: erc20Amount(settings.amount), contractAddress: settings.contract.address, }, @@ -99,10 +101,10 @@ function resolveCollectRequestFor( fee: amount.isZero() ? undefined : { + type: FeeType.COLLECT, amount, contractAddress: settings.contract.address, }, - collectModule: settings.contract.address, public: session.type === SessionType.JustWallet, signless, sponsored, @@ -118,10 +120,10 @@ function resolveCollectRequestFor( params.referrers ?? (args.publication !== collectable ? [args.publication.id] : undefined), fee: { + type: FeeType.COLLECT, amount: erc20Amount(settings.amount), contractAddress: settings.contract.address, }, - collectModule: settings.contract.address, public: session.type === SessionType.JustWallet, signless, sponsored, @@ -138,13 +140,17 @@ function resolveCollectRequestFor( params.referrers ?? (args.publication !== collectable ? [args.publication.id] : undefined), fee: amount.isZero() - ? undefined + ? { + type: FeeType.MINT, + amount: erc20Amount(settings.mintFee), + contractAddress: settings.contract.address, + executorClient: params.executorClient, + } : { + type: FeeType.COLLECT, amount, contractAddress: settings.contract.address, }, - collectModule: settings.contract.address, - executorClient: params.executorClient, public: session.type === SessionType.JustWallet, signless, sponsored,