Skip to content
This repository was archived by the owner on Feb 8, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions internal/verifierapi/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,13 @@ func (v VerifierApi) GetPluginPolicyFees(policyId uuid.UUID) (FeeHistoryDto, err
v.logger.Debug("URL: ", url)
response, err := v.get(url)
if err != nil {
v.logger.WithError(err).Error("failed to get plugin policy fees")
return FeeHistoryDto{}, fmt.Errorf("failed to get plugin policy fees: %w", err)
}
if response.StatusCode == http.StatusNotFound {
v.logger.WithError(fmt.Errorf("policy not found")).Error("policy not found for id: ", policyId.String())
return FeeHistoryDto{}, fmt.Errorf("policy not found")
}

if response.StatusCode != http.StatusOK {
v.logger.WithError(err).Error("failed to get plugin policy fees")
return FeeHistoryDto{}, fmt.Errorf("failed to get plugin policy fees, status code: %d", response.StatusCode)
}

Expand All @@ -87,22 +84,17 @@ func (v VerifierApi) GetPluginPolicyFees(policyId uuid.UUID) (FeeHistoryDto, err
// TODO add auth
func (v VerifierApi) GetPublicKeysFees(ecdsaPublicKey string) (FeeHistoryDto, error) {
url := fmt.Sprintf("/fees/publickey/%s", ecdsaPublicKey)
v.logger.Debug("Getting public key fees for public key: ", ecdsaPublicKey)
v.logger.Debug("URL: ", url)
response, err := v.get(url)
if err != nil {
v.logger.WithError(err).Error("failed to get public key fees")
return FeeHistoryDto{}, fmt.Errorf("failed to get public key fees: %w", err)
}

//TODO - this probably shouldn't be a 404, just an empty wrapped response with 0
if response.StatusCode == http.StatusNotFound {
v.logger.WithError(fmt.Errorf("public key not found")).Error("public key not found for id: ", ecdsaPublicKey)
return FeeHistoryDto{}, fmt.Errorf("public key not found")
}

if response.StatusCode != http.StatusOK {
v.logger.WithError(err).Error("failed to get public key fees")
return FeeHistoryDto{}, fmt.Errorf("failed to get public key fees, status code: %d", response.StatusCode)
}

Expand All @@ -124,12 +116,10 @@ func (v VerifierApi) GetAllPublicKeysFees() (map[string]FeeHistoryDto, error) {
v.logger.Debug("URL: ", url)
response, err := v.get(url)
if err != nil {
v.logger.WithError(err).Error("failed to get all public key fees")
return map[string]FeeHistoryDto{}, fmt.Errorf("failed to get all public key fees: %w", err)
}

if response.StatusCode != http.StatusOK {
v.logger.WithError(err).Error("failed to get all public key fees")
return map[string]FeeHistoryDto{}, fmt.Errorf("failed to get all public key fees, status code: %d", response.StatusCode)
}

Expand Down
1 change: 0 additions & 1 deletion internal/verifierapi/verifierapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ type VerifierApi struct {
}

func NewVerifierApi(url string, logger *logrus.Logger) *VerifierApi {
logger.Debug("New Verifier API created with URL: ", url)
return &VerifierApi{
URL: url,
logger: logger,
Expand Down
77 changes: 16 additions & 61 deletions plugin/fees/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,6 @@ func (fp FeePlugin) GetRecipeSpecification() rtypes.RecipeSchema {
}
}

// This wraps the logger with the plugin name and context "i.e the worker execution".
func (fp *FeePlugin) Log(level logrus.Level, args ...interface{}) {
fp.logger.WithFields(logrus.Fields{
"plugin": "fees",
"context": "execution",
}).Log(level, args...)
}

func (fp *FeePlugin) GetPolicyFees(cfg BaseConfig) error {
return nil
}
Expand All @@ -167,33 +159,31 @@ func (fp *FeePlugin) SigningComplete(ctx context.Context, signature tss.KeysignR
// HANDLER FUNCTIONS

func (fp *FeePlugin) HandleCollections(ctx context.Context, task *asynq.Task) error {
fp.Log(logrus.InfoLevel, "Starting Fee Collection Job")
fp.logger.Info("Starting Fee Collection Job")

// Figure out if we're collecting fees by public key, policy, or plugin id
feeCollectionFormat := FeeCollectionFormat{
FeeCollectionType: FeeCollectionTypeAll,
}
if len(task.Payload()) != 0 {
if err := json.Unmarshal(task.Payload(), &feeCollectionFormat); err != nil {
fp.Log(logrus.ErrorLevel, "Failed to unmarshal fee collection config")
return err
return fmt.Errorf("fp.HandleCollections, failed to unmarshall asynq task payload, %w", err)

Copilot AI Jul 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in error message: 'unmarshall' should be 'unmarshal'. Also consider rephrasing for consistency (e.g., 'failed to unmarshal asynq task payload: %w').

Suggested change
return fmt.Errorf("fp.HandleCollections, failed to unmarshall asynq task payload, %w", err)
return fmt.Errorf("failed to unmarshal asynq task payload: %w", err)

Copilot uses AI. Check for mistakes.
}
}

switch feeCollectionFormat.FeeCollectionType {
case FeeCollectionTypeByPublicKey:
fp.Log(logrus.InfoLevel, "Collecting fees by public key")
fp.logger.Info("Collecting fees by public key")
return fp.collectFeesByPublicKey(feeCollectionFormat.Value)
case FeeCollectionTypeByPolicy:
fp.Log(logrus.InfoLevel, "Collecting fees by policy")
fp.logger.Info("Collecting fees by policy")
return fp.collectFeesByPolicy(feeCollectionFormat.Value)
case FeeCollectionTypeByPluginID:
fp.Log(logrus.InfoLevel, "Collecting fees by plugin id")
fp.logger.Info("Collecting fees by plugin id")

Copilot AI Jul 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch logs an info message but doesn’t return or invoke a handler, causing a silent fallthrough that returns nil. Add a return or handling logic for FeeCollectionTypeByPluginID.

Suggested change
fp.logger.Info("Collecting fees by plugin id")
fp.logger.Info("Collecting fees by plugin id")
return fp.collectFeesByPluginID(feeCollectionFormat.Value)

Copilot uses AI. Check for mistakes.
case FeeCollectionTypeAll:
fp.Log(logrus.InfoLevel, "Collecting fees by all")
fp.logger.Info("Collecting fees by all")
return fp.collectAllFees()
default:
fp.Log(logrus.ErrorLevel, "Invalid fee collection type")
return fmt.Errorf("invalid fee collection type")
}

Expand All @@ -204,45 +194,38 @@ func (fp *FeePlugin) HandleCollections(ctx context.Context, task *asynq.Task) er

// Collects fee data by ... Should only be called by HandleFeeCollections
func (fp *FeePlugin) collectFeesByPublicKey(publicKey string) error {
fp.Log(logrus.DebugLevel, "Collecting fees by policy: ")
feesResponse, err := fp.verifierApi.GetPublicKeysFees(publicKey)
if err != nil {
return fmt.Errorf("failed to get plugin policy fees: %w", err)
}

fp.logger.Debug("Fees response: ", feesResponse)

if feesResponse.FeesPendingCollection > 0 {
fp.Log(logrus.InfoLevel, "Fees pending collection: ", feesResponse.FeesPendingCollection)
fp.logger.Info("Fees pending collection: ", feesResponse.FeesPendingCollection)

feesToCollect := []uuid.UUID{}
checkAmount := 0
for _, fee := range feesResponse.Fees {
fp.Log(logrus.DebugLevel, "Fee: ", fee)
if !fee.Collected {
feesToCollect = append(feesToCollect, fee.ID)
checkAmount += fee.Amount
}
}
if checkAmount != feesResponse.FeesPendingCollection {
fp.Log(logrus.ErrorLevel, "Fees pending collection amount does not match the sum of the fees")
return fmt.Errorf("fees pending collection amount does not match the sum of the fees")
}

fp.Log(logrus.InfoLevel, "Fees to collect: ", feesToCollect)
fp.logger.Info("Fees to collect: ", feesToCollect)

} else {
fp.Log(logrus.InfoLevel, "No fees pending collection")
fp.logger.Info("No fees pending collection")
}

return nil
}

// Collects fee data by ... Should only be called by HandleFeeCollections
// Not yet working
func (fp *FeePlugin) collectFeesByPolicy(policyIdString string) error {
// TODO: implement logic
fp.Log(logrus.DebugLevel, "Collecting fees by policy: ")

policyId, err := uuid.Parse(policyIdString)
if err != nil {
return fmt.Errorf("failed to parse policy id: %w", err)
Expand All @@ -252,31 +235,23 @@ func (fp *FeePlugin) collectFeesByPolicy(policyIdString string) error {
return fmt.Errorf("failed to get plugin policy fees: %w", err)
}

fp.logger.Debug("Fees response: ", feesResponse)

if feesResponse.FeesPendingCollection > 0 {
fp.Log(logrus.InfoLevel, "Fees pending collection: ", feesResponse.FeesPendingCollection)
fp.logger.Info("Fees pending collection: ", feesResponse.FeesPendingCollection)

feesToCollect := []uuid.UUID{}
checkAmount := 0
for _, fee := range feesResponse.Fees {
fp.Log(logrus.DebugLevel, "Fee: ", fee)
if !fee.Collected {
feesToCollect = append(feesToCollect, fee.ID)
checkAmount += fee.Amount
}
}
if checkAmount != feesResponse.FeesPendingCollection {
fp.Log(logrus.ErrorLevel, "Fees pending collection amount does not match the sum of the fees")
return fmt.Errorf("fees pending collection amount does not match the sum of the fees")
}

// fp.buildUSDCEthFeeTransaction(feesToCollect)

// fp.Log(logrus.InfoLevel, "Fees to collect: ", feesToCollect)

} else {
fp.Log(logrus.InfoLevel, "No fees pending collection")
fp.logger.Info("No fees pending collection")
}

return nil
Expand All @@ -285,38 +260,32 @@ func (fp *FeePlugin) collectFeesByPolicy(policyIdString string) error {
// Collects fee data by ... Should only be called by HandleFeeCollections
func (fp *FeePlugin) collectAllFees() error {
ctx := context.Background()
fp.Log(logrus.DebugLevel, "Collecting all fees")
feesResponse, err := fp.verifierApi.GetAllPublicKeysFees()
if err != nil {
fp.Log(logrus.ErrorLevel, "Failed to get plugin policy fees: ", err)
return fmt.Errorf("failed to get plugin policy fees: %w", err)
}

fp.logger.Debug("Fees response: ", feesResponse)

for publicKey, feeHistory := range feesResponse {
//TODO just for testing

if feeHistory.FeesPendingCollection > 0 {

fp.Log(logrus.InfoLevel, "Fees pending collection: ", feeHistory.FeesPendingCollection)
fp.logger.Info("Fees pending collection: ", feeHistory.FeesPendingCollection)

checkAmount := 0
for _, fee := range feeHistory.Fees {
fp.Log(logrus.DebugLevel, "Fee: ", fee)
if !fee.Collected {
checkAmount += fee.Amount
}
}
if checkAmount != feeHistory.FeesPendingCollection {
fp.Log(logrus.ErrorLevel, "Fees pending collection amount does not match the sum of the fees")
return fmt.Errorf("fees pending collection amount does not match the sum of the fees")
}

fp.executeFeeCollection(ctx, publicKey, feeHistory.Fees)

} else {
fp.Log(logrus.InfoLevel, "No fees pending collection for public key: ", publicKey)
fp.logger.Info("No fees pending collection for public key: ", publicKey)
}
}

Expand All @@ -325,53 +294,40 @@ func (fp *FeePlugin) collectAllFees() error {

func (fp *FeePlugin) executeFeeCollection(ctx context.Context, ecdsaPublicKey string, feeIds []verifierapi.FeeDto) error {

fp.Log(logrus.DebugLevel, "Executing fee collection for public key: ", ecdsaPublicKey)

//Get fee policy document
feePolicies, err := fp.db.GetAllPluginPolicies(ctx, ecdsaPublicKey, vtypes.PluginVultisigFees_feee, true)
fp.Log(logrus.DebugLevel, "Fee policies: ", len(feePolicies))
if err != nil {
fp.Log(logrus.DebugLevel, "Failed to get fee policies: ", err)
return fmt.Errorf("failed to get fee policies: %w", err)
}
if len(feePolicies) == 0 {
fp.Log(logrus.DebugLevel, "No fee policies found")
return fmt.Errorf("no fee policies found")
} else if len(feePolicies) > 1 {
fp.Log(logrus.DebugLevel, "Multiple fee policies found")
return fmt.Errorf("multiple fee policies found")
}
feePolicy := feePolicies[0]
fp.Log(logrus.DebugLevel, "Fee policy: ", feePolicy)

//Here we check if the fee collection is already in progress for the public key.
feeRun, err := fp.db.CreateFeeRun(ctx, feePolicy.ID, types.FeeRunStateDraft, feeIds)
if err != nil {
fp.Log(logrus.DebugLevel, "Failed to create fee run: ", err)
return fmt.Errorf("failed to create fee run: %w", err)
}
fp.Log(logrus.DebugLevel, "Fee run created: ", feeRun)
fp.logger.Info("Fee run created: ", feeRun)

//Get vault and check it exists

vaultFileName := vcommon.GetVaultBackupFilename(ecdsaPublicKey, vtypes.PluginVultisigFees_feee.String())
vaultContent, err := fp.vaultStorage.GetVault(vaultFileName)
if err != nil {
// TODO some real error handling here
fp.Log(logrus.DebugLevel, "Failed to get vault: ", err)
return fmt.Errorf("failed to get vault: %w", err)
}
if vaultContent == nil {
// TODO some real error handling here
fp.Log(logrus.DebugLevel, "Vault not found")
return fmt.Errorf("vault not found")
}

keySignRequests, err := fp.ProposeTransactions(feePolicy)
if err != nil {
fp.Log(logrus.DebugLevel, "Failed to propose transactions: ", err)
return fmt.Errorf("failed to propose transactions: %w", err)
}
fp.Log(logrus.DebugLevel, "keySignRequest: ", keySignRequests)

var eg errgroup.Group
for _, keySignRequest := range keySignRequests {
Expand All @@ -382,7 +338,6 @@ func (fp *FeePlugin) executeFeeCollection(ctx context.Context, ecdsaPublicKey st
}
err = eg.Wait()
if err != nil {
fp.logger.WithError(err).Error("eg.Wait")
return fmt.Errorf("eg.Wait: %s, %w", err, asynq.SkipRetry)
}

Expand Down
19 changes: 7 additions & 12 deletions plugin/fees/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P

nonce, err := fp.nonceManager.GetNextNonce(ethAddress)
if err != nil {
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("p.nonceManager.GetNextNonce: %w", err)
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("plugincommon.nonceManager.GetNextNonce: %w", err)

Copilot AI Jul 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error prefix "plugincommon.nonceManager.GetNextNonce" does not match the actual target. It should refer to fp.nonceManager.GetNextNonce or the correct package-level function name to avoid misleading error traces.

Suggested change
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("plugincommon.nonceManager.GetNextNonce: %w", err)
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("fp.nonceManager.GetNextNonce: %w", err)

Copilot uses AI. Check for mistakes.
}

tx, e := plugincommon.GenUnsignedTx(
Expand All @@ -136,7 +136,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P
)

if e != nil {
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("p.genUnsignedTx: %w", e)
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("plugincommon.genUnsignedTx: %w", e)
}

txHex := hex.EncodeToString(tx)
Expand All @@ -151,7 +151,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P
ProposedTxHex: txHex,
})
if e != nil {
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("p.txIndexerService.CreateTx: %w", e)
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("fp.tx_indexer.CreateTx: %w", e)

Copilot AI Jul 3, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference to fp.tx_indexer appears incorrect; the field is named fp.txIndexerService. Update the error prefix and field usage to the correct identifier to ensure accurate context and compilation.

Suggested change
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("fp.tx_indexer.CreateTx: %w", e)
return []vtypes.PluginKeysignRequest{}, fmt.Errorf("fp.txIndexerService.CreateTx: %w", e)

Copilot uses AI. Check for mistakes.
}

// Create signing request
Expand Down Expand Up @@ -220,7 +220,7 @@ func (fp *FeePlugin) IsAlreadyProposed(
if errors.Is(err, storage.ErrNoTx) {
return false, nil
}
return false, fmt.Errorf("p.txIndexerService.GetTxInTimeRange: %w", err)
return false, fmt.Errorf("fp.txIndexerService.GetTxInTimeRange: %w", err)
}

func (fp *FeePlugin) initSign(
Expand All @@ -230,7 +230,6 @@ func (fp *FeePlugin) initSign(
) error {
buf, e := json.Marshal(req)
if e != nil {
fp.logger.WithError(e).Error("json.Marshal")
return fmt.Errorf("json.Marshal: %w", e)
}

Expand All @@ -242,8 +241,7 @@ func (fp *FeePlugin) initSign(
asynq.Queue(tasks.QUEUE_NAME),
)
if e != nil {
fp.logger.WithError(e).Error("p.client.Enqueue")
return fmt.Errorf("p.client.Enqueue: %w", e)
return fmt.Errorf("fp.client.Enqueue: %w", e)
}

for {
Expand All @@ -253,8 +251,7 @@ func (fp *FeePlugin) initSign(
case <-time.After(3 * time.Second):
taskInfo, er := fp.asynqInspector.GetTaskInfo(tasks.QUEUE_NAME, task.ID)
if er != nil {
fp.logger.WithError(er).Error("p.inspector.GetTaskInfo(tasks.QUEUE_NAME, task.ID)")
return fmt.Errorf("p.inspector.GetTaskInfo: %w", er)
return fmt.Errorf("fp.inspector.GetTaskInfo: %w", er)
}
if taskInfo.State != asynq.TaskStateCompleted {
continue
Expand All @@ -267,7 +264,6 @@ func (fp *FeePlugin) initSign(
var res map[string]tss.KeysignResponse
er = json.Unmarshal(taskInfo.Result, &res)
if er != nil {
fp.logger.WithError(er).Error("json.Unmarshal(taskInfo.Result, &res)")
return fmt.Errorf("json.Unmarshal(taskInfo.Result, &res): %w", er)
}

Expand All @@ -278,8 +274,7 @@ func (fp *FeePlugin) initSign(

er = fp.SigningComplete(ctx, sig, req, pluginPolicy)
if er != nil {
fp.logger.WithError(er).Error("p.SigningComplete")
return fmt.Errorf("p.SigningComplete: %w", er)
return fmt.Errorf("fp.SigningComplete: %w", er)
}

fp.logger.WithField("public_key", req.PublicKey).
Expand Down