Skip to content

Commit

Permalink
v1: configure additional mint fees for specific tokens (#460)
Browse files Browse the repository at this point in the history
* v1: configure additional mint fees for specific tokens

v1

Extend TokenMintConfiguration to specify additional fees,
charged in $GALA, in addition to globally-configured fee
quantities for mint operations for specific token classes.

* add feeGateImplementations.ts changes for token-specific mint fees
  • Loading branch information
sentientforest authored Dec 9, 2024
1 parent 552e06f commit 560337d
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 20 deletions.
41 changes: 40 additions & 1 deletion chain-api/src/types/TokenMintConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import BigNumber from "bignumber.js";
import { Exclude, Type } from "class-transformer";
import {
IsBoolean,
Expand All @@ -26,7 +27,7 @@ import {
} from "class-validator";

import { ChainKey, ValidationFailedError } from "../utils";
import { IsUserAlias } from "../validators";
import { BigNumberIsPositive, BigNumberProperty, IsUserAlias } from "../validators";
import { ChainObject } from "./ChainObject";

/**
Expand Down Expand Up @@ -118,6 +119,33 @@ export class BurnToMintConfiguration extends ChainObject {
burnPercentage: number;
}

/**
* @description
*
* Configure additional fees specific to the token being minted.
* These fees will be charged in addition to any base fee
* globally configured for mint-specific contract methods using the
* `MintToken` `feeCode`.
*/
export class MintFeeConfiguration extends ChainObject {
/**
* @description
*
* Specify a flat fee to charge in addition to standard or
* global usage-based fees configured for the `MintToken`
* feeCode. This amount will be added to other fees.
*
* @example
*
* If the `MintToken` `feeCode` specifies a rate of 1 $GALA, setting this property
* to 99 would incur a total fee of 100 $GALA.
*/
@IsOptional()
@BigNumberProperty()
@BigNumberIsPositive()
flatFee: BigNumber;
}

/**
* @description
*
Expand Down Expand Up @@ -200,6 +228,17 @@ export class TokenMintConfiguration extends ChainObject {
@Type(() => PostMintLockConfiguration)
public postMintLock?: PostMintLockConfiguration;

/**
* @description
*
* (optional) configure how GalaChain Fees (paid in $GALA) are handled
* when minting the configured TokenClass.
*/
@IsOptional()
@ValidateNested()
@Type(() => MintFeeConfiguration)
public additionalFee?: MintFeeConfiguration;

@Exclude()
public validatePostProcessingTotals() {
const burnPercentage: number | undefined = this.postMintBurn?.burnPercentage;
Expand Down
35 changes: 18 additions & 17 deletions chaincode/src/fees/feeGateImplementations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import BigNumber from "bignumber.js";
import { plainToInstance } from "class-transformer";

import { authorize } from "../contracts";
import { fetchTokenMintConfiguration } from "../mint";
import { KnownOracles } from "../oracle";
import { GalaChainContext, createValidChainObject } from "../types";
import { getObjectByKey, putChainObject } from "../utils";
Expand Down Expand Up @@ -441,22 +442,11 @@ export async function mintPreProcessing(ctx: GalaChainContext, data: IMintPrePro
const { tokenClass } = data;
const { collection, category, type, additionalKey } = tokenClass;

const mintConfiguration: TokenMintConfiguration | undefined = await getObjectByKey(
ctx,
TokenMintConfiguration,
TokenMintConfiguration.getCompositeKeyFromParts(TokenMintConfiguration.INDEX_KEY, [
collection,
category,
type,
additionalKey
])
).catch((e) => {
const chainError = ChainError.from(e);
if (chainError.matches(ErrorCode.NOT_FOUND)) {
return undefined;
} else {
throw chainError;
}
const mintConfiguration: TokenMintConfiguration | undefined = await fetchTokenMintConfiguration(ctx, {
collection,
category,
type,
additionalKey
});

if (!mintConfiguration) {
Expand Down Expand Up @@ -490,12 +480,23 @@ export async function combinedMintFees(ctx: GalaChainContext, data: ICombinedMin
}
});

const { collection, category, type, additionalKey } = data.tokenClass;
const mintConfiguration: TokenMintConfiguration | undefined = await fetchTokenMintConfiguration(ctx, {
collection,
category,
type,
additionalKey
});

const additionalFeeInGala: BigNumber | undefined = mintConfiguration?.additionalFee?.flatFee;

await galaFeeGate(ctx, {
feeCode: data.feeCode
feeCode: data.feeCode,
// v1 fees requires only callingUser identities pay fees
// uncomment below to require benefiting / initiating user to pay,
// regardless of who executes the method
// activeUser: dto.owner ?? ctx.callingUser
additionalFee: additionalFeeInGala
}).catch((e) => {
if (e instanceof ChainError && e.code === ErrorCode.PAYMENT_REQUIRED) {
paymentErrors.push(e);
Expand Down
10 changes: 8 additions & 2 deletions chaincode/src/fees/galaFeeGate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { payFeeImmediatelyFromBalance } from "./payFeeImmediatelyFromBalance";
export interface GalaFeeGateParams {
feeCode: string;
activeUser?: string | undefined;
additionalFee?: BigNumber | undefined;
}

/**
Expand Down Expand Up @@ -125,14 +126,19 @@ export async function writeUsageAndCalculateFeeAmount(
userFeeThresholdUses
);

const currentCumulativeFees = userFeeThresholdUses.cumulativeFeeQuantity.plus(feeAmount);
const additionalFee: BigNumber = data.additionalFee ?? new BigNumber("0");
const usageFeePlusAnyAdditionalFees = feeAmount.plus(additionalFee);

const currentCumulativeFees = userFeeThresholdUses.cumulativeFeeQuantity.plus(
usageFeePlusAnyAdditionalFees
);

userFeeThresholdUses.cumulativeUses = cumulativeUses;
userFeeThresholdUses.cumulativeFeeQuantity = currentCumulativeFees;

await putChainObject(ctx, userFeeThresholdUses);

return { feeAmount, feeCodeDefinitions, cumulativeUses };
return { feeAmount: usageFeePlusAnyAdditionalFees, feeCodeDefinitions, cumulativeUses };
}

export interface cumulativeUsesAndFeeAmount {
Expand Down
49 changes: 49 additions & 0 deletions chaincode/src/mint/fetchMintConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) Gala Games Inc. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ChainError, ErrorCode, TokenMintConfiguration } from "@gala-chain/api";

import { GalaChainContext } from "../types";
import { getObjectByKey } from "../utils";

export interface IFetchMintConfiguration {
collection: string;
category: string;
type: string;
additionalKey: string;
}

export async function fetchTokenMintConfiguration(ctx: GalaChainContext, data: IFetchMintConfiguration) {
const { collection, category, type, additionalKey } = data;

const mintConfiguration: TokenMintConfiguration | undefined = await getObjectByKey(
ctx,
TokenMintConfiguration,
TokenMintConfiguration.getCompositeKeyFromParts(TokenMintConfiguration.INDEX_KEY, [
collection,
category,
type,
additionalKey
])
).catch((e) => {
const chainError = ChainError.from(e);
if (chainError.matches(ErrorCode.NOT_FOUND)) {
return undefined;
} else {
throw chainError;
}
});

return mintConfiguration;
}
2 changes: 2 additions & 0 deletions chaincode/src/mint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { constructVerifiedMints } from "./constructVerifiedMints";
import { deleteTokenMintConfiguration } from "./deleteTokenMintConfiguration";
import { fetchMintAllowanceSupply, fetchMintAllowanceSupplyForToken } from "./fetchMintAllowanceSupply";
import { fetchTokenMintConfiguration } from "./fetchMintConfiguration";
import { fetchTokenMintConfigurations } from "./fetchMintConfigurations";
import { fetchMintSupply } from "./fetchMintSupply";
import { fetchTokenClassesWithSupply } from "./fetchTokenClassWithSupply";
Expand Down Expand Up @@ -57,6 +58,7 @@ export {
saveTokenMintConfiguration,
validateMintRequest,
fetchMintAllowanceSupply,
fetchTokenMintConfiguration,
fetchTokenMintConfigurations,
fetchMintSupply,
fetchMintAllowanceSupplyForToken,
Expand Down

0 comments on commit 560337d

Please sign in to comment.