Skip to content

Commit

Permalink
fix: fix dust error in Nexa (#4562)
Browse files Browse the repository at this point in the history
  • Loading branch information
huhuanming authored May 10, 2024
1 parent 66d3e67 commit df18e81
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 32 deletions.
21 changes: 0 additions & 21 deletions packages/engine/src/vaults/VaultBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -786,27 +786,6 @@ export abstract class VaultBase extends VaultBaseChainOnly {
return nextNonce;
}

getConfirmedUTXOs<T extends { value: string | number }>(
utxos: T[],
amount: string,
): T[] {
const confirmedUTXOs = utxos.sort((a, b) =>
new BigNumber(b.value).gt(a.value) ? 1 : -1,
);
let sum = new BigNumber(0);
let i = 0;
for (i = 0; i < confirmedUTXOs.length; i += 1) {
sum = sum.plus(confirmedUTXOs[i].value);
if (sum.gt(amount)) {
break;
}
}
if (sum.lt(amount)) {
return [];
}
return confirmedUTXOs.slice(0, i + 1);
}

validateSendAmount(amount: string, tokenBalance: string, to: string) {
return Promise.resolve(true);
}
Expand Down
49 changes: 46 additions & 3 deletions packages/engine/src/vaults/impl/nexa/Vault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,29 @@ export default class Vault extends VaultBase {
return Promise.resolve({} as IDecodedTxLegacy);
}

getConfirmedUTXOs<T extends { value: string | number }>(
utxos: T[],
amount: string,
minTransferAmount = '0',
): T[] {
const transactionAmount = new BigNumber(amount).plus(minTransferAmount);
const confirmedUTXOs = utxos.sort((a, b) =>
new BigNumber(b.value).gt(a.value) ? 1 : -1,
);
let sum = new BigNumber(0);
let i = 0;
for (i = 0; i < confirmedUTXOs.length; i += 1) {
sum = sum.plus(confirmedUTXOs[i].value);
if (sum.gt(transactionAmount)) {
break;
}
}
if (sum.lt(transactionAmount)) {
return [];
}
return confirmedUTXOs.slice(0, i + 1);
}

override async buildEncodedTxFromTransfer(
transferInfo: ITransferInfo,
): Promise<IEncodedTxNexa> {
Expand Down Expand Up @@ -288,6 +311,15 @@ export default class Vault extends VaultBase {
return Promise.resolve(encodedTx);
}

async getMinTransferAmount() {
const network = await this.getNetwork();
return network.settings.minTransferAmount
? new BigNumber(network.settings.minTransferAmount)
.shiftedBy(network.decimals)
.toFixed()
: undefined;
}

override async buildUnsignedTxFromEncodedTx(
encodedTx: IEncodedTxNexa,
): Promise<IUnsignedTxPro> {
Expand All @@ -302,6 +334,7 @@ export default class Vault extends VaultBase {
.shiftedBy(network.decimals)
.plus(encodedTx?.gas || 0)
.toFixed(),
await this.getMinTransferAmount(),
);

if (confirmedUTXOs.length > client.MAX_TX_NUM_VIN) {
Expand Down Expand Up @@ -339,11 +372,21 @@ export default class Vault extends VaultBase {
): Promise<IFeeInfo> {
const network = await this.getNetwork();
const client = await this.getSDKClient();
const estimateSizedSize = estimateSize(encodedTx);
const vinLength = this.getConfirmedUTXOs(
encodedTx.inputs.map((input) => ({
...input,
value: input.satoshis,
})),
new BigNumber(encodedTx.transferInfo?.amount || 0)
.shiftedBy(network.decimals)
.toFixed(),
await this.getMinTransferAmount(),
).length;
const estimateSizedSize = estimateSize(vinLength, encodedTx.outputs);
const remoteEstimateFee = await client.estimateFee(estimateSizedSize);
const localEstimateFee = estimateFee(encodedTx);
const localEstimateFee = estimateFee(vinLength, encodedTx.outputs);
const feeInfo = specifiedFeeRate
? estimateFee(encodedTx, Number(specifiedFeeRate))
? estimateFee(vinLength, encodedTx.outputs, Number(specifiedFeeRate))
: Math.max(remoteEstimateFee, localEstimateFee);
return {
nativeSymbol: network.symbol,
Expand Down
1 change: 0 additions & 1 deletion packages/engine/src/vaults/impl/nexa/sdk/nexa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export class Nexa extends SimpleClient {
async getTransaction(txHash: string): Promise<INexaTransaction> {
return this.rpc.call<INexaTransaction>('blockchain.transaction.get', [
txHash,
true,
]);
}

Expand Down
18 changes: 11 additions & 7 deletions packages/engine/src/vaults/impl/nexa/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,25 +142,29 @@ const DEFAULT_SEQNUMBER = MAXINT;
const FEE_PER_KB = 1000 * 3;
const CHANGE_OUTPUT_MAX_SIZE = 1 + 8 + 1 + 23;

export function estimateSize(encodedTx: IEncodedTxNexa) {
export function estimateSize(
vinlength: number,
vouts: IEncodedTxNexa['outputs'],
) {
let estimatedSize = 4 + 1; // locktime + version
estimatedSize += encodedTx.inputs.length < 253 ? 1 : 3;
encodedTx.inputs.forEach(() => {
estimatedSize += vinlength < 253 ? 1 : 3;
new Array(vinlength).fill(0).forEach(() => {
// type + outpoint + scriptlen + script + sequence + amount
estimatedSize += 1 + 32 + 1 + 100 + 4 + 8;
});
encodedTx.outputs.forEach((output) => {
vouts.forEach((output) => {
const bfr = getScriptBufferFromScriptTemplateOut(output.address);
estimatedSize += convertScriptToPushBuffer(bfr).length + 1 + 8 + 1;
});
return estimatedSize;
}

export function estimateFee(
encodedTx: IEncodedTxNexa,
vinlength: number,
vouts: IEncodedTxNexa['outputs'],
feeRate = FEE_PER_KB / 1000,
): number {
const size = estimateSize(encodedTx);
const size = estimateSize(vinlength, vouts);
const feeWithChange = Math.ceil(
size * feeRate + CHANGE_OUTPUT_MAX_SIZE * feeRate,
);
Expand Down Expand Up @@ -292,7 +296,7 @@ function buildSignatures(encodedTx: IEncodedTxNexa, dbAccountAddress: string) {
new BN(0),
);

const fee = new BN(gas || estimateFee(encodedTx));
const fee = new BN(gas || estimateFee(inputs.length, outputs));
const available = inputAmount.sub(fee);
if (available.lt(new BN(0))) {
console.error(inputAmount.toString(), fee.toString());
Expand Down

0 comments on commit df18e81

Please sign in to comment.