lotus-sdk
Version:
Central repository for several classes of tools for integrating with, and building for, the Lotusia ecosystem
95 lines (94 loc) • 3.57 kB
JavaScript
import { Output } from '../../bitcore/transaction/output.js';
import { Script } from '../../bitcore/script.js';
import { Opcode } from '../../bitcore/opcode.js';
import { DEFAULT_BURN_CONFIG } from './types.js';
export class SwapSigBurnMechanism {
config;
constructor(config) {
this.config = { ...DEFAULT_BURN_CONFIG, ...config };
}
calculateBurnAmount(swapAmount, burnPercentage) {
const percentage = burnPercentage ?? this.config.burnPercentage;
const rawBurn = Math.floor(swapAmount * percentage);
return Math.max(this.config.minimumBurn, Math.min(rawBurn, this.config.maximumBurn));
}
createBurnOutput(burnAmount, poolId, config) {
const burnConfig = config ?? this.config;
const burnId = Buffer.from(burnConfig.burnIdentifier, 'utf8');
const poolIdBuf = Buffer.from(poolId, 'hex');
const versionBuf = Buffer.from([burnConfig.version]);
const script = new Script().add(Opcode.OP_RETURN).add(burnId);
if (burnConfig.poolIdInBurn) {
script.add(poolIdBuf);
}
script.add(versionBuf);
return new Output({
satoshis: burnAmount,
script,
});
}
validateBurn(tx, expectedAmount, expectedPoolId, config) {
const burnConfig = config ?? this.config;
const burnOutput = tx.outputs.find(output => {
const script = output.script;
if (!script || script.chunks.length === 0)
return false;
return script.chunks[0].opcodenum === Opcode.OP_RETURN;
});
if (!burnOutput) {
return false;
}
if (burnOutput.satoshis !== expectedAmount) {
return false;
}
const script = burnOutput.script;
const chunks = script.chunks;
const minChunks = burnConfig.poolIdInBurn ? 4 : 3;
if (chunks.length < minChunks) {
return false;
}
if (chunks[0].opcodenum !== Opcode.OP_RETURN) {
return false;
}
const burnId = chunks[1].buf;
if (!burnId || burnId.toString('utf8') !== burnConfig.burnIdentifier) {
return false;
}
let chunkIndex = 2;
if (burnConfig.poolIdInBurn) {
const poolIdBuf = chunks[chunkIndex].buf;
if (!poolIdBuf || poolIdBuf.toString('hex') !== expectedPoolId) {
return false;
}
chunkIndex++;
}
const versionBuf = chunks[chunkIndex].buf;
if (!versionBuf || versionBuf[0] !== burnConfig.version) {
return false;
}
return true;
}
calculateTotalBurned(participantCount, denomination) {
const burnPerParticipant = this.calculateBurnAmount(denomination);
return participantCount * burnPerParticipant;
}
calculateSybilAttackCost(fakeParticipants, denomination, feePerTx) {
const burnPerParticipant = this.calculateBurnAmount(denomination);
const lockedFunds = fakeParticipants * denomination;
const burnedFunds = fakeParticipants * burnPerParticipant;
const feesFunds = fakeParticipants * 2 * feePerTx;
return {
lockedFunds,
burnedFunds,
feesFunds,
totalIrrecoverable: burnedFunds + feesFunds,
totalCost: lockedFunds + burnedFunds + feesFunds,
};
}
getConfig() {
return { ...this.config };
}
updateConfig(config) {
this.config = { ...this.config, ...config };
}
}