Skip to content

Commit

Permalink
chore: resolve circular dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
janniks committed Feb 5, 2024
1 parent 3c6f408 commit 3ec88d6
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 43 deletions.
41 changes: 0 additions & 41 deletions packages/transactions/src/builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
createSpendingCondition,
createSponsoredAuth,
createStandardAuth,
MultiSigSpendingCondition,
} from './authorization';
import { ClarityValue, PrincipalCV } from './clarity';
import {
Expand All @@ -18,9 +17,7 @@ import {
NonFungibleConditionCode,
PayloadType,
PostConditionMode,
RECOVERABLE_ECDSA_SIG_LENGTH_BYTES,
SingleSigHashMode,
StacksMessageType,
} from './constants';
import { ClarityAbi, validateContractCall } from './contract-abi';
import { estimateFee, getAbi, getNonce } from './fetch';
Expand Down Expand Up @@ -797,41 +794,3 @@ export async function sponsorTransaction(

return signer.transaction;
}

/**
* Estimates transaction byte length
* Context:
* 1) Multi-sig transaction byte length increases by adding signatures
* which causes the incorrect fee estimation because the fee value is set while creating unsigned transaction
* 2) Single-sig transaction byte length remain same due to empty message signature which allocates the space for signature
* @param {transaction} - StacksTransaction object to be estimated
* @return {number} Estimated transaction byte length
*/
export function estimateTransactionByteLength(transaction: StacksTransaction): number {
const hashMode = transaction.auth.spendingCondition.hashMode;
// List of Multi-sig transaction hash modes
const multiSigHashModes = [AddressHashMode.SerializeP2SH, AddressHashMode.SerializeP2WSH];

// Check if its a Multi-sig transaction
if (multiSigHashModes.includes(hashMode)) {
const multiSigSpendingCondition: MultiSigSpendingCondition = transaction.auth
.spendingCondition as MultiSigSpendingCondition;

// Find number of existing signatures if the transaction is signed or partially signed
const existingSignatures = multiSigSpendingCondition.fields.filter(
field => field.contents.type === StacksMessageType.MessageSignature
).length; // existingSignatures will be 0 if its a unsigned transaction

// Estimate total signature bytes size required for this multi-sig transaction
// Formula: totalSignatureLength = (signaturesRequired - existingSignatures) * (SIG_LEN_BYTES + 1 byte of type of signature)
const totalSignatureLength =
(multiSigSpendingCondition.signaturesRequired - existingSignatures) *
(RECOVERABLE_ECDSA_SIG_LENGTH_BYTES + 1);

return transaction.serialize().byteLength + totalSignatureLength;
} else {
// Single-sig transaction
// Signature space already allocated by empty message signature
return transaction.serialize().byteLength;
}
}
7 changes: 5 additions & 2 deletions packages/transactions/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import {
validateHash256,
with0x,
} from '@stacks/common';
import { estimateTransactionByteLength } from './builders';
import { ClarityValue, NoneCV, deserializeCV, serializeCV } from './clarity';
import { NoEstimateAvailableError } from './errors';
import { serializePayload } from './payload';
import { StacksTransaction, deriveNetworkFromTx } from './transaction';
import {
StacksTransaction,
deriveNetworkFromTx,
estimateTransactionByteLength,
} from './transaction';
import { cvToHex, defaultApiFromNetwork, parseReadOnlyResponse } from './utils';
import {
FeeEstimateResponse,
Expand Down
41 changes: 41 additions & 0 deletions packages/transactions/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {
writeUInt32BE,
} from '@stacks/common';
import {
AddressHashMode,
AnchorMode,
anchorModeFrom,
AnchorModeName,
AuthType,
PayloadType,
PostConditionMode,
PubKeyEncoding,
RECOVERABLE_ECDSA_SIG_LENGTH_BYTES,
StacksMessageType,
} from './constants';

Expand All @@ -22,6 +24,7 @@ import {
deserializeAuthorization,
intoInitialSighashAuth,
isSingleSig,
MultiSigSpendingCondition,
nextSignature,
serializeAuthorization,
setFee,
Expand Down Expand Up @@ -313,3 +316,41 @@ export function deriveNetworkFromTx(transaction: StacksTransaction) {
[TransactionVersion.Testnet]: STACKS_TESTNET,
});
}

/**
* Estimates transaction byte length
* Context:
* 1) Multi-sig transaction byte length increases by adding signatures
* which causes the incorrect fee estimation because the fee value is set while creating unsigned transaction
* 2) Single-sig transaction byte length remain same due to empty message signature which allocates the space for signature
* @param {transaction} - StacksTransaction object to be estimated
* @return {number} Estimated transaction byte length
*/
export function estimateTransactionByteLength(transaction: StacksTransaction): number {
const hashMode = transaction.auth.spendingCondition.hashMode;
// List of Multi-sig transaction hash modes
const multiSigHashModes = [AddressHashMode.SerializeP2SH, AddressHashMode.SerializeP2WSH];

// Check if its a Multi-sig transaction
if (multiSigHashModes.includes(hashMode)) {
const multiSigSpendingCondition: MultiSigSpendingCondition = transaction.auth
.spendingCondition as MultiSigSpendingCondition;

// Find number of existing signatures if the transaction is signed or partially signed
const existingSignatures = multiSigSpendingCondition.fields.filter(
field => field.contents.type === StacksMessageType.MessageSignature
).length; // existingSignatures will be 0 if its a unsigned transaction

// Estimate total signature bytes size required for this multi-sig transaction
// Formula: totalSignatureLength = (signaturesRequired - existingSignatures) * (SIG_LEN_BYTES + 1 byte for type of signature)
const totalSignatureLength =
(multiSigSpendingCondition.signaturesRequired - existingSignatures) *
(RECOVERABLE_ECDSA_SIG_LENGTH_BYTES + 1);

return transaction.serialize().byteLength + totalSignatureLength;
} else {
// Single-sig transaction
// Signature space already allocated by empty message signature
return transaction.serialize().byteLength;
}
}

0 comments on commit 3ec88d6

Please sign in to comment.