Skip to content

Commit

Permalink
Refactor mint
Browse files Browse the repository at this point in the history
  • Loading branch information
opcatdev committed Nov 4, 2024
1 parent 25f59cd commit 24ed24f
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 92 deletions.
1 change: 0 additions & 1 deletion packages/cli/src/commands/deploy/deploy.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ export class DeployCommand extends BoardcastCommand {
},
],
metadata,
2,
minter,
scalePremine,
);
Expand Down
96 changes: 75 additions & 21 deletions packages/cli/src/commands/mint/ft.open-minter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,34 +145,45 @@ export function createOpenMinterState(
newMinter: number,
): {
splitAmountList: bigint[];
minterStates: OpenMinterState[];
minterStates: Array<OpenMinterState | OpenMinterV2State>;
} {
const scaledInfo = scaleConfig(metadata.info as OpenMinterTokenInfo);

const premine = !isPriemined ? scaledInfo.premine : 0n;
const limit = scaledInfo.limit;
let splitAmountList = OpenMinterProto.getSplitAmountList(
premine + remainingSupply,
mintAmount,
limit,
newMinter,
);
const tokenP2TR = toP2tr(metadata.tokenAddr);

let splitAmountList = []
const minterStates: Array<OpenMinterState | OpenMinterV2State> = [];
if (metadata.info.minterMd5 == MinterType.OPEN_MINTER_V2) {
splitAmountList = OpenMinterV2Proto.getSplitAmountList(
remainingSupply,
isPriemined,
scaledInfo.premine,
);
}
const tokenP2TR = toP2tr(metadata.tokenAddr);

const minterStates: Array<OpenMinterState> = [];
for (let i = 0; i < splitAmountList.length; i++) {
const amount = splitAmountList[i];
if (amount > 0n) {
const minterState = OpenMinterProto.create(tokenP2TR, true, amount);
minterStates.push(minterState);
for (let i = 0; i < splitAmountList.length; i++) {
const amount = splitAmountList[i];
if (amount > 0n) {
const minterState = OpenMinterV2Proto.create(tokenP2TR, true, amount);
minterStates.push(minterState);
}
}
} else {
splitAmountList = OpenMinterProto.getSplitAmountList(
premine + remainingSupply,
mintAmount,
limit,
newMinter,
);


for (let i = 0; i < splitAmountList.length; i++) {
const amount = splitAmountList[i];
if (amount > 0n) {
const minterState = OpenMinterProto.create(tokenP2TR, true, amount);
minterStates.push(minterState);
}
}
}

Expand Down Expand Up @@ -207,10 +218,13 @@ export async function openMint(
feeRate: number,
feeUtxos: UTXO[],
metadata: TokenMetadata,
newMinter: number /* number of new minter utxo */,
minterContract: OpenMinterContract,
mintAmount: bigint,
): Promise<string | Error> {
): Promise<{
newFeeUtxo: UTXO,
newMinters: OpenMinterContract[];
txId: string;
} | Error> {
const {
utxo: minterUtxo,
state: { protocolState, data: preState },
Expand All @@ -234,12 +248,16 @@ export async function openMint(
preState.isPremined,
getRemainSupply(preState, tokenInfo.minterMd5),
metadata,
newMinter,
2,
);

for (let i = 0; i < minterStates.length; i++) {
const minterState = minterStates[i];
newState.updateDataList(i, OpenMinterProto.toByteString(minterState));
if(tokenInfo.minterMd5 === MinterType.OPEN_MINTER_V2) {
newState.updateDataList(i, OpenMinterV2Proto.toByteString(minterState as OpenMinterV2State));
} else {
newState.updateDataList(i, OpenMinterProto.toByteString(minterState as OpenMinterState));
}
}

const tokenState = CAT20Proto.create(mintAmount, tokenReceiver);
Expand Down Expand Up @@ -295,8 +313,10 @@ export async function openMint(
}),
);

let newMinterCount = 0;
for (let i = 0; i < splitAmountList.length; i++) {
if (splitAmountList[i] > 0n) {
newMinterCount++;
revealTx.addOutput(
new btc.Transaction.Output({
script: new btc.Script(minterUtxo.script),
Expand Down Expand Up @@ -373,7 +393,7 @@ export async function openMint(
const changeAmount =
revealTx.inputAmount -
vsize * feeRate -
Postage.MINTER_POSTAGE * newMinter -
Postage.MINTER_POSTAGE * newMinterCount -
Postage.TOKEN_POSTAGE;

if (changeAmount < 546) {
Expand Down Expand Up @@ -451,5 +471,39 @@ export async function openMint(
return res;
}
spendService.updateSpends(revealTx);
return res;

const newMinters: OpenMinterContract[] = [];

for (let i = 0; i < splitAmountList.length; i++) {
if (splitAmountList[i] > 0n) {
newMinters.push({
utxo: {
txId: revealTx.id,
outputIndex: i + 1,
satoshis: Postage.MINTER_POSTAGE,
script: minterUtxo.script,
},
state: {
protocolState: newState,
data: minterStates[i]
}
})
}
}

const outputIndex = revealTx.outputs.length -1;

const newFeeUtxo = {
txId: revealTx.id,
outputIndex: outputIndex,
satoshis: revealTx.outputs[outputIndex].satoshis,
script: revealTx.outputs[outputIndex].script.toHex(),
}


return {
newMinters,
txId: revealTx.id,
newFeeUtxo
};
}
153 changes: 83 additions & 70 deletions packages/cli/src/commands/mint/mint.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Command, Option } from 'nest-commander';
import {
getUtxos,
OpenMinterTokenInfo,
getTokenMinter,
logerror,
getTokenMinterCount,
isOpenMinter,
Expand All @@ -13,6 +12,8 @@ import {
btc,
TokenMetadata,
MinterType,
OpenMinterContract,
getTokenMinter,
} from 'src/common';
import { getRemainSupply, openMint } from './ft.open-minter';
import { ConfigService, SpendService, WalletService } from 'src/providers';
Expand Down Expand Up @@ -50,6 +51,54 @@ export class MintCommand extends BoardcastCommand {
super(spendService, walletService, configService);
}

fixAmount = (
minter: OpenMinterContract,
token: TokenMetadata,
scaledInfo: OpenMinterTokenInfo,
amount?: bigint,
) => {
const minterState = minter.state.data;
if (minterState.isPremined && amount > scaledInfo.limit) {
console.error('The number of minted tokens exceeds the limit!');
return null;
}

const limit = scaledInfo.limit;

if (!minter.state.data.isPremined && scaledInfo.premine > 0n) {
if (typeof amount === 'bigint') {
if (amount !== scaledInfo.premine) {
throw new Error(
`first mint amount should equal to premine ${scaledInfo.premine}`,
);
}
} else {
amount = scaledInfo.premine;
}
} else {
amount = amount || limit;
if (token.info.minterMd5 === MinterType.OPEN_MINTER_V1) {
if (getRemainSupply(minter.state.data, token.info.minterMd5) < limit) {
console.warn(
`small limit of ${unScaleByDecimals(limit, token.info.decimals)} in the minter UTXO!`,
);
log(`retry to mint token [${token.info.symbol}] ...`);
return null;
}
amount =
amount > getRemainSupply(minter.state.data, token.info.minterMd5)
? getRemainSupply(minter.state.data, token.info.minterMd5)
: amount;
} else if (
token.info.minterMd5 == MinterType.OPEN_MINTER_V2 &&
amount != limit
) {
console.warn(`can only mint at the exactly amount of ${limit} at once`);
amount = limit;
}
}
return amount;
};
async cat_cli_run(
passedParams: string[],
options?: MintCommandOptions,
Expand Down Expand Up @@ -120,87 +169,51 @@ export class MintCommand extends BoardcastCommand {
offset,
);

if (minter == null) {
if (minter === null) {
console.error('No available minter UTXO found!');
continue;
}

const minterState = minter.state.data;
if (minterState.isPremined && amount > scaledInfo.limit) {
console.error('The number of minted tokens exceeds the limit!');
return;
}

const limit = scaledInfo.limit;
if (isOpenMinter(token.info.minterMd5)) {
amount = this.fixAmount(minter, token, scaledInfo, amount);

if (!minter.state.data.isPremined && scaledInfo.premine > 0n) {
if (typeof amount === 'bigint') {
if (amount !== scaledInfo.premine) {
throw new Error(
`first mint amount should equal to premine ${scaledInfo.premine}`,
);
}
} else {
amount = scaledInfo.premine;
if (amount === null) {
return;
}
} else {
amount = amount || limit;
if (token.info.minterMd5 === MinterType.OPEN_MINTER_V1) {
if (
getRemainSupply(minter.state.data, token.info.minterMd5) < limit
) {
console.warn(
`small limit of ${unScaleByDecimals(limit, token.info.decimals)} in the minter UTXO!`,
);

const res = await openMint(
this.configService,
this.walletService,
this.spendService,
feeRate,
feeUtxos,
token,
minter,
amount,
);

if (res instanceof Error) {
if (needRetry(res)) {
// throw these error, so the caller can handle it.
log(`retry to mint token [${token.info.symbol}] ...`);
await sleep(6);
continue;
} else {
logerror(`mint token [${token.info.symbol}] failed`, res);
return;
}
amount =
amount >
getRemainSupply(minter.state.data, token.info.minterMd5)
? getRemainSupply(minter.state.data, token.info.minterMd5)
: amount;
} else if (
token.info.minterMd5 == MinterType.OPEN_MINTER_V2 &&
amount != limit
) {
console.warn(
`can only mint at the exactly amount of ${limit} at once`,
);
amount = limit;
}
}

const mintTxIdOrErr = await openMint(
this.configService,
this.walletService,
this.spendService,
feeRate,
feeUtxos,
token,
2,
minter,
amount,
);

if (mintTxIdOrErr instanceof Error) {
if (needRetry(mintTxIdOrErr)) {
// throw these error, so the caller can handle it.
log(`retry to mint token [${token.info.symbol}] ...`);
await sleep(6);
continue;
} else {
logerror(
`mint token [${token.info.symbol}] failed`,
mintTxIdOrErr,
const { txId } = res;

console.log(
`Minting ${unScaleByDecimals(amount, token.info.decimals)} ${token.info.symbol} tokens in txid: ${txId} ...`,
);

return;
}
} else {
throw new Error('unkown minter!');
}

console.log(
`Minting ${unScaleByDecimals(amount, token.info.decimals)} ${token.info.symbol} tokens in txid: ${mintTxIdOrErr} ...`,
);
return;
}

console.error(`mint token [${token.info.symbol}] failed`);
Expand All @@ -223,7 +236,7 @@ export class MintCommand extends BoardcastCommand {
if (res !== null) {
const { contracts: tokenContracts } = res;

if (tokenContracts.length > 1) {
if (tokenContracts.length >= 4) {
const cachedTxs: Map<string, btc.Transaction> = new Map();
console.info(`Start merging your [${metadata.info.symbol}] tokens ...`);

Expand Down

0 comments on commit 24ed24f

Please sign in to comment.