From 7fe2dda431f8c3360b564e059d6b0da363b8b9a5 Mon Sep 17 00:00:00 2001 From: Garry Sharp <> Date: Thu, 17 Jul 2025 18:07:47 +0400 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20Small=20bug=20fixes=20for=20?= =?UTF-8?q?fees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/vultisig/fee.yml | 2 ++ fee.server.example.json | 2 +- internal/scheduler/scheduler.go | 13 ++++++++++++ payroll.worker.example.json | 2 +- plugin/fees/config.go | 2 ++ plugin/fees/transaction.go | 37 +++++++++++++-------------------- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/etc/vultisig/fee.yml b/etc/vultisig/fee.yml index c261f67..b04666a 100644 --- a/etc/vultisig/fee.yml +++ b/etc/vultisig/fee.yml @@ -5,3 +5,5 @@ collector_whitelist_addresses: - 0x7d760c17d798a7A9a4c4AcAf311A02dC95972503 - 0x5BB06B9C5e4f7624Df7100Badb2F5AA1C86d8498 collector_address: 0x7d760c17d798a7A9a4c4AcAf311A02dC95972503 +usdc_address: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 +verifier_token: localhost-fee-key diff --git a/fee.server.example.json b/fee.server.example.json index 0c9c70c..428c3b0 100644 --- a/fee.server.example.json +++ b/fee.server.example.json @@ -15,7 +15,7 @@ "password": "password" }, "block_storage": { - "host": "http://localhost:9100", + "host": "http://minio-plugin:9000", "region": "us-east-1", "access_key": "minioadmin", "secret": "minioadmin", diff --git a/internal/scheduler/scheduler.go b/internal/scheduler/scheduler.go index 255a5f3..cf990bf 100644 --- a/internal/scheduler/scheduler.go +++ b/internal/scheduler/scheduler.go @@ -184,6 +184,19 @@ func (s *SchedulerService) CreateTimeTrigger(ctx context.Context, policy vtypes. return s.db.CreateTimeTriggerTx(ctx, dbTx, *trigger) } +func (s *SchedulerService) GetScheduleFromPolicy(policy vtypes.PluginPolicy) (*rtypes.Schedule, error) { + recipe, err := base64.StdEncoding.DecodeString(policy.Recipe) + if err != nil { + return nil, fmt.Errorf("base64.StdEncoding.DecodeString: %w", err) + } + + var p rtypes.Policy + if err := proto.Unmarshal(recipe, &p); err != nil { + return nil, fmt.Errorf("failed to parse policy schedule: %w", err) + } + return p.Schedule, nil +} + func (s *SchedulerService) GetTriggerFromPolicy(policy vtypes.PluginPolicy) (*types.TimeTrigger, error) { recipe, err := base64.StdEncoding.DecodeString(policy.Recipe) if err != nil { diff --git a/payroll.worker.example.json b/payroll.worker.example.json index 06759cb..ca7738f 100644 --- a/payroll.worker.example.json +++ b/payroll.worker.example.json @@ -24,7 +24,7 @@ "password": "password" }, "block_storage": { - "host": "http://localhost:9100", + "host": "http://minio-plugin:9000", "region": "us-east-1", "access_key": "minioadmin", "secret": "minioadmin", diff --git a/plugin/fees/config.go b/plugin/fees/config.go index a90d18b..242bced 100644 --- a/plugin/fees/config.go +++ b/plugin/fees/config.go @@ -34,6 +34,8 @@ type FeeConfig struct { CollectorWhitelistAddresses []string `mapstructure:"collector_whitelist_addresses"` // A list of whitelisted addresses for which fee transactions are collected against. These can include previous addresses. Fee plugins with a recipient address that is not in this list will not be processed. CollectorAddress string `mapstructure:"collector_address"` // This address is what is used for new policies. Fee policies created with a different address will be rejected. MaxFeeAmount uint64 `mapstructure:"max_fee_amount"` // Policies that are created/submitted which do not have this amount will be rejected. + UsdcAddress string `mapstructure:"usdc_address"` // The address of the USDC token on the Ethereum blockchain. + VerifierToken string `mapstructure:"verifier_token"` // The token to use for the verifier API. } type ConfigOption func(*FeeConfig) error diff --git a/plugin/fees/transaction.go b/plugin/fees/transaction.go index bec94d6..927fd97 100644 --- a/plugin/fees/transaction.go +++ b/plugin/fees/transaction.go @@ -21,7 +21,6 @@ import ( "github.com/vultisig/recipes/engine" reth "github.com/vultisig/recipes/ethereum" rtypes "github.com/vultisig/recipes/types" - rutil "github.com/vultisig/recipes/util" "github.com/vultisig/verifier/address" vcommon "github.com/vultisig/verifier/common" "github.com/vultisig/verifier/tx_indexer/pkg/storage" @@ -39,6 +38,15 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P return nil, fmt.Errorf("failed to get vault from policy: %v", err) } + // ERC20 USDC Token List + var usdc *reth.Token = &reth.Token{ + ChainId: 1, + Address: fp.config.UsdcAddress, + Name: "USD Coin", + Symbol: "USDC", + Decimals: 6, + } + // Get the ethereum derived addresses from the vaults master public key ethAddress, _, _, err := address.GetAddress(vault.PublicKeyEcdsa, vault.HexChainCode, vcommon.Ethereum) if err != nil { @@ -50,12 +58,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P if err != nil { return nil, fmt.Errorf("failed to get recipe from policy: %v", err) } - echain, err := chain.GetChain("ethereum") - if err != nil { - return nil, fmt.Errorf("failed to get ethereum chain: %v", err) - } - ethchain := echain.(*reth.Ethereum) chain := vcommon.Ethereum txs := []vtypes.PluginKeysignRequest{} @@ -64,8 +67,8 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P // This section of code goes through the rules in the fee policy. It looks for the recipient of the fee collection policy and extracts it. If other data is found throws an error as they're unsupported rules. var recipient string // The address specified in the fee policy. - switch rule.Id { - case "allow-usdc-transfer-to-collector": + switch rule.Resource { + case "ethereum.usdc.transfer": for _, constraint := range rule.ParameterConstraints { if constraint.ParameterName == "recipient" { if constraint.Constraint.Type != rtypes.ConstraintType_CONSTRAINT_TYPE_FIXED { @@ -82,16 +85,6 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P return nil, fmt.Errorf("recipient is not set in policy") } - // This section of code is used to get the token address for the fee collection (just eth usdc for now) - resourcePath, err := rutil.ParseResource(rule.Resource) - if err != nil { - return nil, fmt.Errorf("failed to parse resource: %v", err) - } - token, found := ethchain.GetToken(resourcePath.ProtocolId) - if !found { - return nil, fmt.Errorf("failed to get token: %v", resourcePath.ProtocolId) - } - // Here we call the verifier api to get a list of fees that have the same public key as the signed policy document. feeHistory, err := fp.verifierApi.GetPublicKeysFees(policy.PublicKey) if err != nil { @@ -108,7 +101,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P chain, policy.PluginID, policy.ID, - token.Address, + usdc.Address, recipient, fromTime, toTime, @@ -118,7 +111,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P "recipient": recipient, "amount": amount, "chain_id": chain, - "token_id": token.Address, + "token_id": usdc.Address, }).Info("transaction already proposed, skipping") return nil, nil } @@ -126,7 +119,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P tx, err := fp.eth.MakeAnyTransfer(ctx, gcommon.HexToAddress(ethAddress), gcommon.HexToAddress(recipient), - gcommon.HexToAddress(token.Address), + gcommon.HexToAddress(usdc.Address), big.NewInt(int64(amount))) if err != nil { return nil, fmt.Errorf("failed to generate unsigned transaction: %w", err) @@ -138,7 +131,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P PluginID: policy.PluginID, PolicyID: policy.ID, ChainID: chain, - TokenID: token.Address, + TokenID: usdc.Address, FromPublicKey: policy.PublicKey, ToPublicKey: recipient, ProposedTxHex: txHex, From 188c8d216ee6f41b053ad781f25ad1e9873b406e Mon Sep 17 00:00:00 2001 From: Garry Sharp <> Date: Mon, 21 Jul 2025 14:12:14 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Bumped=20verifier=20im?= =?UTF-8?q?port=20version=20and=20tidied?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 60 ++-------------------------------------------------------- 2 files changed, 3 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index bcf2c5c..8766e4f 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/vultisig/commondata v0.0.0-20250430024109-a2492623ef05 github.com/vultisig/mobile-tss-lib v0.0.0-20250316003201-2e7e570a4a74 github.com/vultisig/recipes v0.0.0-20250719180414-00d6b1584122 - github.com/vultisig/verifier v0.0.0-20250719183957-66bbb5d90164 + github.com/vultisig/verifier v0.0.0-20250719200941-de5b88138d5c github.com/vultisig/vultiserver v0.0.0-20250715212748-4b23f9849e4b golang.org/x/sync v0.12.0 google.golang.org/protobuf v1.36.6 diff --git a/go.sum b/go.sum index da01880..e6329d1 100644 --- a/go.sum +++ b/go.sum @@ -745,66 +745,10 @@ github.com/vultisig/go-wrappers v0.0.0-20250403041248-86911e8aa33f h1:124Xlloih1 github.com/vultisig/go-wrappers v0.0.0-20250403041248-86911e8aa33f/go.mod h1:UfGCxUQW08kiwxyNBiHwXe+ePPuBmHVVS+BS51aU/Jg= github.com/vultisig/mobile-tss-lib v0.0.0-20250316003201-2e7e570a4a74 h1:goqwk4nQ/NEVIb3OPP9SUx7/u9ZfsUIcd5fIN/e4DVU= github.com/vultisig/mobile-tss-lib v0.0.0-20250316003201-2e7e570a4a74/go.mod h1:nOykk4nOy1L3yXtLSlYvVsgizBnCQ3tR2N5uwGPdvaM= -github.com/vultisig/recipes v0.0.0-20250710152947-d15b238437ae h1:Per1QtZamO2PiQLxzTJP5SNjg6INtn83IG0c0585/s8= -github.com/vultisig/recipes v0.0.0-20250710152947-d15b238437ae/go.mod h1:Ci29kT+x5vPxLCRvIrbVNzM+JIMjDbVvvaLTzli5kYQ= -github.com/vultisig/recipes v0.0.0-20250719170828-98457020ba89 h1:fl2mXU+iEjwzVnEXIh3LuTV4QuY/nE3AhhvqabDVkV4= -github.com/vultisig/recipes v0.0.0-20250719170828-98457020ba89/go.mod h1:Ci29kT+x5vPxLCRvIrbVNzM+JIMjDbVvvaLTzli5kYQ= -github.com/vultisig/recipes v0.0.0-20250719172653-42606aebb7ce h1:JOZsnMz2VeF41uH0ZRHiGsUwA2pDaXPR6CCOxKaBRJc= -github.com/vultisig/recipes v0.0.0-20250719172653-42606aebb7ce/go.mod h1:Ci29kT+x5vPxLCRvIrbVNzM+JIMjDbVvvaLTzli5kYQ= -github.com/vultisig/recipes v0.0.0-20250719173546-d9e9db26d802 h1:5ElUP9U8qLicd2uS8FfjSWuKvo7aopAnKW34IM6DJfo= -github.com/vultisig/recipes v0.0.0-20250719173546-d9e9db26d802/go.mod h1:Ci29kT+x5vPxLCRvIrbVNzM+JIMjDbVvvaLTzli5kYQ= github.com/vultisig/recipes v0.0.0-20250719180414-00d6b1584122 h1:pt1wftezaJRC1x1BSBQeVXj4kjLwbz8dw102vX79R3I= github.com/vultisig/recipes v0.0.0-20250719180414-00d6b1584122/go.mod h1:Ci29kT+x5vPxLCRvIrbVNzM+JIMjDbVvvaLTzli5kYQ= -github.com/vultisig/verifier v0.0.0-20250717202157-c35288fbeca7 h1:zLhxfMkNhYcs9npkD2EU7gdT6Iw/2pkxBwyJfTvmhd4= -github.com/vultisig/verifier v0.0.0-20250717202157-c35288fbeca7/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718124644-379bc749509c h1:ge8pQJwre4WhdiC6T3DqdGF+Dt41pRL/HYRgq1XO0rA= -github.com/vultisig/verifier v0.0.0-20250718124644-379bc749509c/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718162147-4f0c328849fd h1:u9NHj7VbhVV/ZmxvN/jyjigM8afKUjptv6IpTGqqsKE= -github.com/vultisig/verifier v0.0.0-20250718162147-4f0c328849fd/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718162726-9ef0a99df956 h1:KwrMs2LqXrK7PsaB0xdVbDRYw2zJviM8ahZOqXm8g04= -github.com/vultisig/verifier v0.0.0-20250718162726-9ef0a99df956/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718163156-76f64393d1a3 h1:aesdVawwixShx6zGY/74f1IV6fKxpqwvjm2ZpSyo/f8= -github.com/vultisig/verifier v0.0.0-20250718163156-76f64393d1a3/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718164759-2117b150abd3 h1:j9kgD0Rs6uJenyygc5+c5zb0HIIsZd7T0CWTBd4HLDE= -github.com/vultisig/verifier v0.0.0-20250718164759-2117b150abd3/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718171906-a95b9be1fd7b h1:82HZZKd/WvDliHlCfMcG9MQwiItNgZq9reZ9FRLyJqA= -github.com/vultisig/verifier v0.0.0-20250718171906-a95b9be1fd7b/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718173959-1ede91390259 h1:6emVhqmvX7qvBj8o2XWjZ+OpuWt+pGu9QZKGJQxYxnw= -github.com/vultisig/verifier v0.0.0-20250718173959-1ede91390259/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718175404-5214d042f14f h1:yeqYKLJqKAkVGK0F+t+PZCAAmxCpo5/BgW0lRNJu4tk= -github.com/vultisig/verifier v0.0.0-20250718175404-5214d042f14f/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718175739-eaca1f75ff1d h1:IZuD0mhZiy1NxyiBp4PPWguwnTZ3EHErUeHJG1sGOt4= -github.com/vultisig/verifier v0.0.0-20250718175739-eaca1f75ff1d/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718181015-882f4e8670bd h1:k+4oQcz9Tk10VKqCS5ZCW+vN8yrQhoOZUaud0uslPQE= -github.com/vultisig/verifier v0.0.0-20250718181015-882f4e8670bd/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718203532-9489403ecf6e h1:eq7iLm8siD17UiwLWfPK3dq3MsG6TkY4jSF96WzKEYQ= -github.com/vultisig/verifier v0.0.0-20250718203532-9489403ecf6e/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718203943-d2547dddc48c h1:TGvDwed4LuqUExEJF7fVo/MBxhRaNt65JH6Vukmi23o= -github.com/vultisig/verifier v0.0.0-20250718203943-d2547dddc48c/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718204848-36ac00c5d197 h1:AX6iyuRvcaZXlFOzvTSDS1XA67pxhsU0em+nOtW6lvQ= -github.com/vultisig/verifier v0.0.0-20250718204848-36ac00c5d197/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718205327-16f1dc8864d3 h1:4zQsGj+hdUNnFb/0J6FUmoTtSBGau7e0lfobj16cXIM= -github.com/vultisig/verifier v0.0.0-20250718205327-16f1dc8864d3/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718205929-74fe22a4f0be h1:QbB+PToXGjbZJAsn/LJz7ETRGPdAP8YPXDWLUeBNHeE= -github.com/vultisig/verifier v0.0.0-20250718205929-74fe22a4f0be/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718210420-2769ddbe964d h1:PXljtGD/MMrDv59jQyPaHRK8VREvPK1rM2R8aG8lZ2c= -github.com/vultisig/verifier v0.0.0-20250718210420-2769ddbe964d/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718211252-60d4356f5430 h1:x8VDQfXTE5Y49gbF9UJv2ADL0gSJTNStgOlauLEQyI0= -github.com/vultisig/verifier v0.0.0-20250718211252-60d4356f5430/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250718212050-f155e61b03e1 h1:nPAWgWzFRcV0FWWy07HSidxIvFdkB2NzvHU6Pw08iPg= -github.com/vultisig/verifier v0.0.0-20250718212050-f155e61b03e1/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250719115605-424195a79403 h1:Zo9T0AdsbrUPcVj6YMD4qrAzGyOfWMo8nBVBDIyxR+U= -github.com/vultisig/verifier v0.0.0-20250719115605-424195a79403/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250719164136-8f30676bad91 h1:9a8yuTmtiPjf0ieah/36vZRjFQ85+gcTJXAG07+0xYQ= -github.com/vultisig/verifier v0.0.0-20250719164136-8f30676bad91/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250719165606-1da8cb862647 h1:MSkEXaEx5JoTpTVFAOrSiYPWkQ84GyW+ZoqZb4CkJS8= -github.com/vultisig/verifier v0.0.0-20250719165606-1da8cb862647/go.mod h1:erFFbF94mKpX0Jq1azlmpaGMKiRbrfmnTZaPDG3zUe8= -github.com/vultisig/verifier v0.0.0-20250719182115-a7edc7e932fd h1:x1VY7DiARNWdoeCDn5e4kCjqvGJf8inDaLg34Bqccss= -github.com/vultisig/verifier v0.0.0-20250719182115-a7edc7e932fd/go.mod h1:9f3yGSZWKZeXn30mU+/brufkbkLoGlFmNLKOpRbQgeI= -github.com/vultisig/verifier v0.0.0-20250719183158-c3bd2be013e2 h1:23TaWlwn9z1W5C5+UliF+1falgw3eZrydNU0DXqmFFk= -github.com/vultisig/verifier v0.0.0-20250719183158-c3bd2be013e2/go.mod h1:9f3yGSZWKZeXn30mU+/brufkbkLoGlFmNLKOpRbQgeI= -github.com/vultisig/verifier v0.0.0-20250719183957-66bbb5d90164 h1:RD2boHHVoaSyHAz8Wo+Nx4uOlaQ1uaCnFhBSDflv2lo= -github.com/vultisig/verifier v0.0.0-20250719183957-66bbb5d90164/go.mod h1:9f3yGSZWKZeXn30mU+/brufkbkLoGlFmNLKOpRbQgeI= +github.com/vultisig/verifier v0.0.0-20250719200941-de5b88138d5c h1:kPH5+uxReDp7OAOUaG6WZxqj0Ujacs2ho5mRmr/qqzY= +github.com/vultisig/verifier v0.0.0-20250719200941-de5b88138d5c/go.mod h1:9f3yGSZWKZeXn30mU+/brufkbkLoGlFmNLKOpRbQgeI= github.com/vultisig/vultiserver v0.0.0-20250715212748-4b23f9849e4b h1:Ed2DOWo8fA0KG6e36rzUmGpxcOQjmWTbxWyvUbI5by8= github.com/vultisig/vultiserver v0.0.0-20250715212748-4b23f9849e4b/go.mod h1:HwP2IgW6Mcu/gX8paFuKvfibrGE9UmPgkOFTub6dskM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= From e0fbae5de8525a885a70fde7cc924e6276323dbf Mon Sep 17 00:00:00 2001 From: Garry Sharp <> Date: Mon, 21 Jul 2025 20:57:44 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8E=A8=20Continuation=20of=20fee=20wo?= =?UTF-8?q?rk,=20on=20top=20of=20small=20bug=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/server_config.go | 1 - cmd/fees/{worker => config}/config.go | 9 +++- cmd/fees/server/config.go | 53 ------------------- cmd/fees/server/main.go | 6 ++- cmd/fees/worker/main.go | 21 +++++++- fee.server.example.json | 6 ++- fee.worker.example.json | 6 ++- plugin/fees/fees.go | 5 ++ plugin/fees/transaction.go | 75 ++++++++------------------- 9 files changed, 65 insertions(+), 117 deletions(-) rename cmd/fees/{worker => config}/config.go (89%) delete mode 100644 cmd/fees/server/config.go diff --git a/api/server_config.go b/api/server_config.go index 1c38dec..b08702c 100644 --- a/api/server_config.go +++ b/api/server_config.go @@ -10,6 +10,5 @@ type ServerConfig struct { Host string `mapstructure:"host" json:"host,omitempty"` Port int64 `mapstructure:"port" json:"port,omitempty"` EncryptionSecret string `mapstructure:"encryption_secret" json:"encryption_secret,omitempty"` - VerifierUrl string `mapstructure:"verifier_url" json:"verifier_url,omitempty"` //The url of the verifier (i.e. the counter party to sign transactions). VaultsFilePath string `mapstructure:"vaults_file_path" json:"vaults_file_path,omitempty"` //This is just for testing locally } diff --git a/cmd/fees/worker/config.go b/cmd/fees/config/config.go similarity index 89% rename from cmd/fees/worker/config.go rename to cmd/fees/config/config.go index 7dc56d1..08e5c01 100644 --- a/cmd/fees/worker/config.go +++ b/cmd/fees/config/config.go @@ -1,4 +1,4 @@ -package main +package config import ( "fmt" @@ -11,8 +11,15 @@ import ( "github.com/vultisig/plugin/storage" ) +type verifier struct { + URL string `mapstructure:"url"` + Token string `mapstructure:"token"` + PartyPrefix string `mapstructure:"party_prefix"` +} + type CoreConfig struct { Server api.ServerConfig `mapstructure:"server" json:"server"` + Verifier verifier Database struct { DSN string `mapstructure:"dsn" json:"dsn,omitempty"` } `mapstructure:"database" json:"database,omitempty"` diff --git a/cmd/fees/server/config.go b/cmd/fees/server/config.go deleted file mode 100644 index 7cd9fe5..0000000 --- a/cmd/fees/server/config.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/spf13/viper" - "github.com/vultisig/verifier/vault_config" - - "github.com/vultisig/plugin/api" - "github.com/vultisig/plugin/storage" -) - -type CoreConfig struct { - Server api.ServerConfig `mapstructure:"server" json:"server"` - Database struct { - DSN string `mapstructure:"dsn" json:"dsn,omitempty"` - } `mapstructure:"database" json:"database,omitempty"` - BaseConfigPath string `mapstructure:"base_config_path" json:"base_config_path,omitempty"` - Redis storage.RedisConfig `mapstructure:"redis" json:"redis,omitempty"` - BlockStorage vault_config.BlockStorage `mapstructure:"block_storage" json:"block_storage,omitempty"` - Datadog struct { - Host string `mapstructure:"host" json:"host,omitempty"` - Port string `mapstructure:"port" json:"port,omitempty"` - } `mapstructure:"datadog" json:"datadog"` -} - -func GetConfigure() (*CoreConfig, error) { - configName := os.Getenv("VS_CONFIG_NAME") - if configName == "" { - configName = "config" - } - - return ReadConfig(configName) -} - -func ReadConfig(configName string) (*CoreConfig, error) { - viper.SetConfigName(configName) - viper.AddConfigPath(".") - viper.AutomaticEnv() - - viper.SetDefault("Server.VaultsFilePath", "vaults") - - if err := viper.ReadInConfig(); err != nil { - return nil, fmt.Errorf("fail to reading config file, %w", err) - } - var cfg CoreConfig - err := viper.Unmarshal(&cfg) - if err != nil { - return nil, fmt.Errorf("unable to decode into struct, %w", err) - } - return &cfg, nil -} diff --git a/cmd/fees/server/main.go b/cmd/fees/server/main.go index 768e9ab..6a2c153 100644 --- a/cmd/fees/server/main.go +++ b/cmd/fees/server/main.go @@ -13,6 +13,7 @@ import ( "github.com/vultisig/verifier/vault" "github.com/vultisig/plugin/api" + feeconfig "github.com/vultisig/plugin/cmd/fees/config" "github.com/vultisig/plugin/plugin/fees" "github.com/vultisig/plugin/storage" "github.com/vultisig/plugin/storage/postgres" @@ -21,7 +22,7 @@ import ( func main() { ctx := context.Background() - cfg, err := GetConfigure() + cfg, err := feeconfig.GetConfigure() if err != nil { panic(err) } @@ -80,6 +81,7 @@ func main() { feePlugin, err := fees.NewFeePlugin( db, + nil, logger, cfg.BaseConfigPath, vaultStorage, @@ -88,7 +90,7 @@ func main() { client, feePluginConfig, cfg.Server.EncryptionSecret, - cfg.Server.VerifierUrl, + cfg.Verifier.URL, ) if err != nil { logger.Fatalf("failed to create fee plugin,err: %s", err) diff --git a/cmd/fees/worker/main.go b/cmd/fees/worker/main.go index 44f4993..64dd50a 100644 --- a/cmd/fees/worker/main.go +++ b/cmd/fees/worker/main.go @@ -8,10 +8,13 @@ import ( "github.com/DataDog/datadog-go/statsd" "github.com/hibiken/asynq" "github.com/sirupsen/logrus" + "github.com/vultisig/plugin/internal/keysign" "github.com/vultisig/verifier/tx_indexer" "github.com/vultisig/verifier/tx_indexer/pkg/storage" "github.com/vultisig/verifier/vault" + "github.com/vultisig/vultiserver/relay" + feeconfig "github.com/vultisig/plugin/cmd/fees/config" "github.com/vultisig/plugin/internal/tasks" "github.com/vultisig/plugin/plugin/fees" "github.com/vultisig/plugin/storage/postgres" @@ -20,7 +23,7 @@ import ( func main() { ctx := context.Background() - cfg, err := GetConfigure() + cfg, err := feeconfig.GetConfigure() if err != nil { panic(err) } @@ -92,8 +95,22 @@ func main() { logger.Fatalf("failed to create fees config,err: %s", err) } + signer := keysign.NewSigner( + logger.WithField("pkg", "keysign.Signer").Logger, + relay.NewRelayClient(cfg.VaultServiceConfig.Relay.Server), + []keysign.Emitter{ + keysign.NewVerifierEmitter(cfg.Verifier.URL, cfg.Verifier.Token), + keysign.NewPluginEmitter(asynqClient, tasks.TypeKeySignDKLS, tasks.QUEUE_NAME), + }, + []string{ + cfg.Verifier.PartyPrefix, + cfg.VaultServiceConfig.LocalPartyPrefix, + }, + ) + feePlugin, err := fees.NewFeePlugin( postgressDB, + signer, logger, cfg.BaseConfigPath, vaultStorage, @@ -102,7 +119,7 @@ func main() { asynqClient, feePluginConfig, cfg.VaultServiceConfig.EncryptionSecret, - cfg.Server.VerifierUrl, + cfg.Verifier.URL, ) if err != nil { logger.Fatalf("failed to create fee plugin,err: %s", err) diff --git a/fee.server.example.json b/fee.server.example.json index 428c3b0..bd1d67f 100644 --- a/fee.server.example.json +++ b/fee.server.example.json @@ -1,9 +1,11 @@ { + "verifier": { + "url": "verifier:8080" + }, "server": { "host": "localhost", "port": 8080, - "encryption_secret": "test123", - "verifier_url": "http://host.docker.internal:8080" + "encryption_secret": "test123" }, "database": { "dsn": "postgres://myuser:mypassword@plugin-db:5432/vultisig-fee?sslmode=disable" diff --git a/fee.worker.example.json b/fee.worker.example.json index 96f2b19..717066b 100644 --- a/fee.worker.example.json +++ b/fee.worker.example.json @@ -1,6 +1,8 @@ { - "server": { - "verifier_url": "http://host.docker.internal:8080" + "verifier": { + "url": "http://verifier:8080", + "token": "localhost-apikey", + "party_prefix": "verifier" }, "vault_service": { "relay": { diff --git a/plugin/fees/fees.go b/plugin/fees/fees.go index 8d42a87..4203534 100644 --- a/plugin/fees/fees.go +++ b/plugin/fees/fees.go @@ -9,6 +9,7 @@ import ( "github.com/google/uuid" "github.com/hibiken/asynq" "github.com/sirupsen/logrus" + "github.com/vultisig/plugin/internal/keysign" vcommon "github.com/vultisig/verifier/common" "github.com/vultisig/verifier/plugin" "github.com/vultisig/verifier/tx_indexer" @@ -34,6 +35,7 @@ var _ plugin.Plugin = (*FeePlugin)(nil) type FeePlugin struct { vaultService *vault.ManagementService vaultStorage *vault.BlockStorageImp + signer *keysign.Signer db storage.DatabaseStorage eth *evm.SDK logger logrus.FieldLogger @@ -46,6 +48,7 @@ type FeePlugin struct { } func NewFeePlugin(db storage.DatabaseStorage, + signer *keysign.Signer, logger logrus.FieldLogger, baseConfigPath string, vaultStorage *vault.BlockStorageImp, @@ -55,6 +58,7 @@ func NewFeePlugin(db storage.DatabaseStorage, feeConfig *FeeConfig, encryptionSecret string, verifierUrl string) (*FeePlugin, error) { + if db == nil { return nil, fmt.Errorf("database storage cannot be nil") } @@ -93,6 +97,7 @@ func NewFeePlugin(db storage.DatabaseStorage, return &FeePlugin{ db: db, eth: evm.NewSDK(ethEvmChainID, rpcClient, rpcClient.Client()), + signer: signer, logger: logger.WithField("plugin", "fees"), config: feeConfig, verifierApi: verifierApi, diff --git a/plugin/fees/transaction.go b/plugin/fees/transaction.go index 927fd97..6b8a7c0 100644 --- a/plugin/fees/transaction.go +++ b/plugin/fees/transaction.go @@ -3,7 +3,6 @@ package fees import ( "context" "encoding/hex" - "encoding/json" "errors" "fmt" "math/big" @@ -11,12 +10,10 @@ import ( "time" "github.com/google/uuid" - "github.com/hibiken/asynq" "github.com/sirupsen/logrus" "github.com/vultisig/mobile-tss-lib/tss" "github.com/vultisig/plugin/common" "github.com/vultisig/plugin/internal/scheduler" - "github.com/vultisig/plugin/internal/tasks" "github.com/vultisig/recipes/chain" "github.com/vultisig/recipes/engine" reth "github.com/vultisig/recipes/ethereum" @@ -154,7 +151,7 @@ func (fp *FeePlugin) ProposeTransactions(policy vtypes.PluginPolicy) ([]vtypes.P Hash: txHex, }, }, - SessionID: uuid.New().String(), + SessionID: "", HexEncryptionKey: "", PolicyID: policy.ID, PluginID: policy.PluginID.String(), @@ -215,21 +212,6 @@ func (fp *FeePlugin) initSign( pluginPolicy vtypes.PluginPolicy, runId uuid.UUID, ) error { - buf, e := json.Marshal(req) - if e != nil { - return fmt.Errorf("failed to marshal key sign request: %w", e) - } - - task, e := fp.asynqClient.Enqueue( - asynq.NewTask(tasks.TypeKeySignDKLS, buf), - asynq.MaxRetry(0), - asynq.Timeout(5*time.Minute), - asynq.Retention(10*time.Minute), - asynq.Queue(tasks.QUEUE_NAME), - ) - if e != nil { - return fmt.Errorf("failed to enqueue key sign task: %w", e) - } if runId != uuid.Nil { if len(req.Messages) != 1 { @@ -245,44 +227,29 @@ func (fp *FeePlugin) initSign( } } - for { - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(3 * time.Second): - taskInfo, er := fp.asynqInspector.GetTaskInfo(tasks.QUEUE_NAME, task.ID) - if er != nil { - return fmt.Errorf("failed to get task info: %w", er) - } - if taskInfo.State != asynq.TaskStateCompleted { - continue - } - if taskInfo.Result == nil { - fp.logger.Info("taskInfo.Result is nil, skipping") - return nil - } - - var res map[string]tss.KeysignResponse - er = json.Unmarshal(taskInfo.Result, &res) - if er != nil { - return fmt.Errorf("failed to unmarshal task result: %w", er) - } - - var sig tss.KeysignResponse - for _, v := range res { // one sig for evm (map with 1 key) - sig = v - } + sigs, err := fp.signer.Sign(ctx, req) + if err != nil { + fp.logger.WithError(err).Error("Keysign failed") + return fmt.Errorf("failed to sign transaction: %w", err) + } - er = fp.SigningComplete(ctx, sig, req, pluginPolicy) - if er != nil { - return fmt.Errorf("failed to sign and broadcast transaction: %w", er) - } + if len(sigs) != 1 { + fp.logger. + WithField("sigs_count", len(sigs)). + Error("expected only 1 message+sig per request for evm") + return fmt.Errorf("failed to sign transaction: invalid signature count: %d", len(sigs)) + } + var sig tss.KeysignResponse + for _, s := range sigs { + sig = s + } - fp.logger.WithField("public_key", req.PublicKey). - Info("successfully signed and broadcasted") - return nil - } + err = fp.SigningComplete(ctx, sig, req, pluginPolicy) + if err != nil { + fp.logger.WithError(err).Error("failed to complete signing process (broadcast tx)") + return fmt.Errorf("failed to complete signing process: %w", err) } + return nil } func (fp *FeePlugin) ValidateProposedTransactions(policy vtypes.PluginPolicy, txs []vtypes.PluginKeysignRequest) error {