diff --git a/api/plugin.go b/api/plugin.go index 1c32d92..4414660 100644 --- a/api/plugin.go +++ b/api/plugin.go @@ -206,8 +206,12 @@ func (s *Server) GetPolicySchema(c echo.Context) error { } func (s *Server) GetRecipeSpecification(c echo.Context) error { - recipeSpec := s.plugin.GetRecipeSpecification() - return c.JSON(http.StatusOK, &recipeSpec) + recipeSpec, err := s.plugin.GetRecipeSpecification() + if err != nil { + s.logger.WithError(err).Error("Failed to get recipe spec") + return c.JSON(http.StatusInternalServerError, NewErrorResponse("failed to get recipe spec")) + } + return c.JSON(http.StatusOK, recipeSpec) } func (s *Server) verifyPolicySignature(policy vtypes.PluginPolicy) bool { diff --git a/api/server.go b/api/server.go index 25e9d75..28613ed 100644 --- a/api/server.go +++ b/api/server.go @@ -115,7 +115,6 @@ func (s *Server) StartServer() error { // policy mode is always available since it is used by both verifier server and plugin server pluginGroup.POST("/policy", s.CreatePluginPolicy) pluginGroup.PUT("/policy", s.UpdatePluginPolicyById) - pluginGroup.GET("/policy/schema", s.GetPolicySchema) pluginGroup.GET("/recipe-specification", s.GetRecipeSpecification) pluginGroup.DELETE("/policy/:policyId", s.DeletePluginPolicyById) diff --git a/go.mod b/go.mod index 8766e4f..e07ab47 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/google/uuid v1.6.0 github.com/hibiken/asynq v0.25.1 github.com/jackc/pgx/v5 v5.7.4 + github.com/kaptinlin/jsonschema v0.4.6 github.com/labstack/echo/v4 v4.13.3 github.com/labstack/gommon v0.4.2 github.com/pressly/goose/v3 v3.24.2 @@ -17,12 +18,12 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.20.1 github.com/stretchr/testify v1.10.0 - github.com/vultisig/commondata v0.0.0-20250430024109-a2492623ef05 + github.com/vultisig/commondata v0.0.0-20250710214228-61d9ed8f7778 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-20250719200941-de5b88138d5c + github.com/vultisig/recipes v0.0.0-20250723142134-153c7f486070 + github.com/vultisig/verifier v0.0.0-20250723150319-a51c59a884bf github.com/vultisig/vultiserver v0.0.0-20250715212748-4b23f9849e4b - golang.org/x/sync v0.12.0 + golang.org/x/sync v0.14.0 google.golang.org/protobuf v1.36.6 ) @@ -86,12 +87,16 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect github.com/golang/glog v1.2.4 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976 // indirect + github.com/gotnospirit/messageformat v0.0.0-20221001023931-dfe49f1eb092 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.1 // indirect @@ -104,6 +109,7 @@ require ( github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect + github.com/kaptinlin/go-i18n v0.1.4 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -169,7 +175,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/otiai10/primes v0.4.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/robfig/cron/v3 v3.0.1 github.com/sagikazarmark/locafero v0.7.0 // indirect @@ -186,7 +192,7 @@ require ( golang.org/x/crypto v0.36.0 golang.org/x/net v0.38.0 // indirect golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/text v0.25.0 // indirect golang.org/x/time v0.9.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index e6329d1..b01e87c 100644 --- a/go.sum +++ b/go.sum @@ -301,6 +301,10 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -370,6 +374,10 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976 h1:b70jEaX2iaJSPZULSUxKtm73LBfsCrMsIlYCUgNGSIs= +github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976/go.mod h1:ZGQeOwybjD8lkCjIyJfqR5LD2wMVHJ31d6GdPxoTsWY= +github.com/gotnospirit/messageformat v0.0.0-20221001023931-dfe49f1eb092 h1:c7gcNWTSr1gtLp6PyYi3wzvFCEcHJ4YRobDgqmIgf7Q= +github.com/gotnospirit/messageformat v0.0.0-20221001023931-dfe49f1eb092/go.mod h1:ZZAN4fkkful3l1lpJwF8JbW41ZiG9TwJ2ZlqzQovBNU= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -464,6 +472,10 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kaptinlin/go-i18n v0.1.4 h1:wCiwAn1LOcvymvWIVAM4m5dUAMiHunTdEubLDk4hTGs= +github.com/kaptinlin/go-i18n v0.1.4/go.mod h1:g1fn1GvTgT4CiLE8/fFE1hboHWJ6erivrDpiDtCcFKg= +github.com/kaptinlin/jsonschema v0.4.6 h1:vOSFg5tjmfkOdKg+D6Oo4fVOM/pActWu/ntkPsI1T64= +github.com/kaptinlin/jsonschema v0.4.6/go.mod h1:1DUd7r5SdyB2ZnMtyB7uLv64dE3zTFTiYytDCd+AEL0= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -585,8 +597,8 @@ github.com/otiai10/primes v0.4.0/go.mod h1:UrIZFvOIqbXG0dvYr0EiZ9iMd+RdUSc7qs1+U github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= @@ -739,16 +751,16 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vultisig/commondata v0.0.0-20250430024109-a2492623ef05 h1:yNZhAu3L1PrbWzVEmwZcSOdU8rGe8WbghsQxMuoO6KA= -github.com/vultisig/commondata v0.0.0-20250430024109-a2492623ef05/go.mod h1:UMc5q0Myab+BvzAe67UQrXTXwKGYNxK7bky7DJM+dl8= +github.com/vultisig/commondata v0.0.0-20250710214228-61d9ed8f7778 h1:XJ1hoo37JKGLmfxD4wYhXO8TJFBdUBnbxxK+zagJ4c4= +github.com/vultisig/commondata v0.0.0-20250710214228-61d9ed8f7778/go.mod h1:UMc5q0Myab+BvzAe67UQrXTXwKGYNxK7bky7DJM+dl8= github.com/vultisig/go-wrappers v0.0.0-20250403041248-86911e8aa33f h1:124Xlloih1FOOXv/HTdgl4syIRBa/xfKFXAecrZSPQE= 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-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-20250719200941-de5b88138d5c h1:kPH5+uxReDp7OAOUaG6WZxqj0Ujacs2ho5mRmr/qqzY= -github.com/vultisig/verifier v0.0.0-20250719200941-de5b88138d5c/go.mod h1:9f3yGSZWKZeXn30mU+/brufkbkLoGlFmNLKOpRbQgeI= +github.com/vultisig/recipes v0.0.0-20250723142134-153c7f486070 h1:AcE6x2dxkl/4P/TxaMJ70pa2BcZ3+FJWnVmlPVAq4Dk= +github.com/vultisig/recipes v0.0.0-20250723142134-153c7f486070/go.mod h1:30NOW5y2BnMCmEYFeVls3NhxkbMvuv7BNyRQfoFhGIM= +github.com/vultisig/verifier v0.0.0-20250723150319-a51c59a884bf h1:3VhxFQR0oJEieaajNDvKlOGBDyTBbSMJSxow3zwUlmw= +github.com/vultisig/verifier v0.0.0-20250723150319-a51c59a884bf/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= @@ -861,8 +873,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -927,8 +939,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 3e37636..75ab79e 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -2,12 +2,15 @@ package plugin import ( "encoding/base64" + "encoding/json" "fmt" + "github.com/kaptinlin/jsonschema" "github.com/vultisig/recipes/engine" rtypes "github.com/vultisig/recipes/types" vtypes "github.com/vultisig/verifier/types" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/structpb" ) func ValidatePluginPolicy(policyDoc vtypes.PluginPolicy, spec *rtypes.RecipeSchema) error { @@ -28,3 +31,21 @@ func ValidatePluginPolicy(policyDoc vtypes.PluginPolicy, spec *rtypes.RecipeSche } return nil } + +func RecipeConfiguration(jsonSchema map[string]any) (*structpb.Struct, error) { + b, err := json.Marshal(jsonSchema) + if err != nil { + return nil, fmt.Errorf("failed to marshal schema: %w", err) + } + + _, err = jsonschema.NewCompiler().Compile(b) + if err != nil { + return nil, fmt.Errorf("failed to compile schema: %w", err) + } + + pb, err := structpb.NewStruct(jsonSchema) + if err != nil { + return nil, fmt.Errorf("failed to build pb schema: %w", err) + } + return pb, nil +} diff --git a/plugin/common/constants.go b/plugin/common/constants.go deleted file mode 100644 index 8de783f..0000000 --- a/plugin/common/constants.go +++ /dev/null @@ -1,13 +0,0 @@ -package common - -// ANY CONSTANTS THAT ARE USED IN MULTIPLE PLUGINS SHOULD BE DEFINED HERE. Like ERC20 ABI. - -const Erc20ABI = `[{ - "name": "transfer", - "type": "function", - "inputs": [ - {"name": "recipient", "type": "address"}, - {"name": "amount", "type": "uint256"} - ], - "outputs": [{"name": "", "type": "bool"}] -}]` diff --git a/plugin/dca/dca.go b/plugin/dca/dca.go index 599b2c2..22e1ffb 100644 --- a/plugin/dca/dca.go +++ b/plugin/dca/dca.go @@ -771,7 +771,7 @@ func (p *DCAPlugin) completePolicy(ctx context.Context, policy vtypes.PluginPoli return nil } -func (p *DCAPlugin) GetRecipeSpecification() *rtypes.RecipeSchema { +func (p *DCAPlugin) GetRecipeSpecification() (*rtypes.RecipeSchema, error) { return &rtypes.RecipeSchema{ Version: 1, // Schema version ScheduleVersion: 1, // Schedule specification version @@ -829,5 +829,5 @@ func (p *DCAPlugin) GetRecipeSpecification() *rtypes.RecipeSchema { MinVultisigVersion: 1, SupportedChains: []string{"ethereum"}, }, - } + }, nil } diff --git a/plugin/fees/policy.go b/plugin/fees/policy.go index 139f364..cc6a3fa 100644 --- a/plugin/fees/policy.go +++ b/plugin/fees/policy.go @@ -1,6 +1,8 @@ package fees import ( + "fmt" + "github.com/vultisig/plugin/internal/plugin" rtypes "github.com/vultisig/recipes/types" vtypes "github.com/vultisig/verifier/types" @@ -16,10 +18,14 @@ import ( */ func (fp *FeePlugin) ValidatePluginPolicy(policyDoc vtypes.PluginPolicy) error { - return plugin.ValidatePluginPolicy(policyDoc, fp.GetRecipeSpecification()) + spec, err := fp.GetRecipeSpecification() + if err != nil { + return fmt.Errorf("failed to get recipe spec: %w", err) + } + return plugin.ValidatePluginPolicy(policyDoc, spec) } -func (fp *FeePlugin) GetRecipeSpecification() *rtypes.RecipeSchema { +func (fp *FeePlugin) GetRecipeSpecification() (*rtypes.RecipeSchema, error) { return &rtypes.RecipeSchema{ Version: 1, // Schema version ScheduleVersion: 1, // Schedule specification version @@ -57,5 +63,5 @@ func (fp *FeePlugin) GetRecipeSpecification() *rtypes.RecipeSchema { MinVultisigVersion: 1, SupportedChains: []string{"ethereum"}, }, - } + }, nil } diff --git a/plugin/payroll/policy.go b/plugin/payroll/policy.go index 86d6360..5e1e57e 100644 --- a/plugin/payroll/policy.go +++ b/plugin/payroll/policy.go @@ -50,5 +50,10 @@ func (p *Plugin) ValidateProposedTransactions(policy vtypes.PluginPolicy, txs [] } func (p *Plugin) ValidatePluginPolicy(policyDoc vtypes.PluginPolicy) error { - return plugin.ValidatePluginPolicy(policyDoc, p.GetRecipeSpecification()) + spec, err := p.GetRecipeSpecification() + if err != nil { + return fmt.Errorf("failed to build recipe spec: %w", err) + } + + return plugin.ValidatePluginPolicy(policyDoc, spec) } diff --git a/plugin/payroll/transaction.go b/plugin/payroll/transaction.go index cb3e7e3..bd79e82 100644 --- a/plugin/payroll/transaction.go +++ b/plugin/payroll/transaction.go @@ -11,24 +11,24 @@ import ( "sync" "time" + gcommon "github.com/ethereum/go-ethereum/common" etypes "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" - "github.com/vultisig/recipes/ethereum" - "github.com/vultisig/recipes/sdk/evm" - "github.com/vultisig/verifier/tx_indexer/pkg/storage" - "github.com/vultisig/vultiserver/contexthelper" - "golang.org/x/sync/errgroup" - - gcommon "github.com/ethereum/go-ethereum/common" "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/plugin" "github.com/vultisig/plugin/internal/scheduler" + "github.com/vultisig/recipes/ethereum" + "github.com/vultisig/recipes/sdk/evm" rtypes "github.com/vultisig/recipes/types" "github.com/vultisig/verifier/address" vcommon "github.com/vultisig/verifier/common" + "github.com/vultisig/verifier/tx_indexer/pkg/storage" vtypes "github.com/vultisig/verifier/types" + "github.com/vultisig/vultiserver/contexthelper" + "golang.org/x/sync/errgroup" "github.com/vultisig/plugin/internal/types" ) @@ -333,7 +333,45 @@ func (p *Plugin) SigningComplete( return nil } -func (p *Plugin) GetRecipeSpecification() *rtypes.RecipeSchema { +const ( + startDate = "start-date" +) + +const ( + frequency = "frequency" + + daily = "daily" + weekly = "weekly" + biWeekly = "bi-weekly" + monthly = "monthly" +) + +func (p *Plugin) GetRecipeSpecification() (*rtypes.RecipeSchema, error) { + cfg, err := plugin.RecipeConfiguration(map[string]any{ + "type": "object", + "properties": map[string]any{ + startDate: map[string]any{ + "type": "string", + "format": "date-time", + }, + frequency: map[string]any{ + "type": "string", + "enum": []any{ + daily, + weekly, + biWeekly, + monthly, + }, + }, + }, + "required": []any{ + frequency, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to build pb recipe config: %w", err) + } + return &rtypes.RecipeSchema{ Version: 1, // Schema version ScheduleVersion: 1, // Schedule specification version @@ -382,13 +420,13 @@ func (p *Plugin) GetRecipeSpecification() *rtypes.RecipeSchema { rtypes.ScheduleFrequency_SCHEDULE_FREQUENCY_BIWEEKLY, rtypes.ScheduleFrequency_SCHEDULE_FREQUENCY_MONTHLY, }, - MaxScheduledExecutions: -1, // infinite }, + Configuration: cfg, Requirements: &rtypes.PluginRequirements{ MinVultisigVersion: 1, SupportedChains: []string{"ethereum"}, }, - } + }, nil } func (p *Plugin) genUnsignedTx(