diff --git a/go.mod b/go.mod index 8ecc2eaf9..492aac927 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,10 @@ require ( github.com/andybalholm/brotli v1.1.1 github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c github.com/bytecodealliance/wasmtime-go/v28 v28.0.0 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dominikbraun/graph v0.23.0 github.com/fxamacker/cbor/v2 v2.5.0 + github.com/gagliardetto/utilz v0.1.3 github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 github.com/go-playground/validator/v10 v10.25.0 github.com/go-viper/mapstructure/v2 v2.4.0 @@ -75,15 +77,16 @@ require ( require ( github.com/apache/arrow-go/v18 v18.3.0 // indirect + github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bufbuild/protocompile v0.14.1 // indirect + github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 // indirect github.com/cloudevents/sdk-go/v2 v2.16.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fatih/color v1.18.0 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -96,6 +99,7 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect + github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.3 // indirect @@ -107,10 +111,13 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.35 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -123,6 +130,8 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.16.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sanity-io/litter v1.5.5 // indirect github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20250430163438-97d324ef9061 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -136,7 +145,9 @@ require ( golang.org/x/mod v0.26.0 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect golang.org/x/text v0.27.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index f68994c64..eb6d94a01 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,16 @@ github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c h1:cxQVoh6kY+c4b0HUchHjGWBI8288VhH50qxKG3hdEg0= github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c/go.mod h1:3XzxudkrYVUvbduN/uI2fl4lSrMSzU0+3RCu2mpnfx8= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 h1:gfAMKE626QEuKG3si0pdTRcr/YEbBoxY+3GOH3gWvl4= +github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytecodealliance/wasmtime-go/v28 v28.0.0 h1:aBU8cexP2rPZ0Qz488kvn2NXvWZHL2aG1/+n7Iv+xGc= @@ -40,6 +44,7 @@ github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMe github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -58,6 +63,9 @@ github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADi github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gagliardetto/hashsearch v0.0.0-20191005111333-09dd671e19f9/go.mod h1:513DXpQPzeRo7d4dsCP3xO3XI8hgvruMl9njxyQeraQ= +github.com/gagliardetto/utilz v0.1.3 h1:A+asc+6/3a9qNBrgticApj3yW5F7y4TaJd8Ijg+o0zM= +github.com/gagliardetto/utilz v0.1.3/go.mod h1:b+rGFkRHz3HWJD0RYMzat47JyvbTtpE0iEcYTRJTLLA= github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -128,6 +136,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwn github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= +github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 h1:BpJ2o0OR5FV7vrkDYfXYVJQeMNWa8RhklZOpW2ITAIQ= +github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= @@ -209,6 +219,7 @@ github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQe github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -244,6 +255,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= +github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= @@ -267,6 +280,7 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -284,11 +298,14 @@ github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9 github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= @@ -420,6 +437,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -449,6 +467,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -464,6 +483,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= @@ -477,6 +497,7 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -505,6 +526,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -530,6 +553,7 @@ golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -584,6 +608,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/types/solana/anchoridl.go b/pkg/types/solana/anchoridl.go new file mode 100644 index 000000000..470b882d9 --- /dev/null +++ b/pkg/types/solana/anchoridl.go @@ -0,0 +1,508 @@ +package solana + +/* + copied from https://github.com/gagliardetto/anchor-go where the IDL definition is not importable due to being defined + in the `main` package. +*/ + +import ( + "encoding/json" + "fmt" + + "github.com/davecgh/go-spew/spew" + "github.com/gagliardetto/utilz" +) + +// https://github.com/project-serum/anchor/blob/97e9e03fb041b8b888a9876a7c0676d9bb4736f3/ts/src/idl.ts +type IDL struct { + Version string `json:"version"` + Name string `json:"name"` + Instructions []IdlInstruction `json:"instructions"` + Accounts IdlTypeDefSlice `json:"accounts,omitempty"` + Types IdlTypeDefSlice `json:"types,omitempty"` + Events []IdlEvent `json:"events,omitempty"` + Errors []IdlErrorCode `json:"errors,omitempty"` + Constants []IdlConstant `json:"constants,omitempty"` +} + +type IdlConstant struct { + Name string + Type IdlType + Value string +} + +type IdlTypeDefSlice []IdlTypeDef + +func (named IdlTypeDefSlice) GetByName(name string) *IdlTypeDef { + for i := range named { + v := named[i] + if v.Name == name { + return &v + } + } + return nil +} + +type IdlEvent struct { + Name string `json:"name"` + Fields []IdlEventField `json:"fields"` +} + +type IdlEventField struct { + Name string `json:"name"` + Type IdlType `json:"type"` + Index bool `json:"index"` +} + +type IdlInstruction struct { + Name string `json:"name"` + Docs []string `json:"docs"` // @custom + Accounts IdlAccountItemSlice `json:"accounts"` + Args []IdlField `json:"args"` +} + +type IdlAccountItemSlice []IdlAccountItem + +func (slice IdlAccountItemSlice) NumAccounts() (count int) { + for _, item := range slice { + if item.IdlAccount != nil { + count++ + } + + if item.IdlAccounts != nil { + count += item.IdlAccounts.Accounts.NumAccounts() + } + } + + return count +} + +// type IdlAccountItem = IdlAccount | IdlAccounts; +type IdlAccountItem struct { + IdlAccount *IdlAccount + IdlAccounts *IdlAccounts +} + +func (env *IdlAccountItem) UnmarshalJSON(data []byte) error { + var temp interface{} + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + if temp == nil { + return fmt.Errorf("envelope is nil: %v", env) + } + + switch v := temp.(type) { + case map[string]interface{}: + if len(v) == 0 { + return nil + } + + _, hasAccounts := v["accounts"] + _, hasIsMut := v["isMut"] + + if hasAccounts == hasIsMut { + return fmt.Errorf("invalid idl structure: expected exactly one of 'accounts' or 'isMut'") + } + + if hasAccounts { + return utilz.TranscodeJSON(temp, &env.IdlAccounts) + } + + return utilz.TranscodeJSON(temp, &env.IdlAccount) + default: + return fmt.Errorf("unknown kind: %s", spew.Sdump(temp)) + } +} + +func (env IdlAccountItem) MarshalJSON() ([]byte, error) { + if (env.IdlAccount == nil) == (env.IdlAccounts == nil) { + return nil, fmt.Errorf("invalid structure: expected either IdlAccount or IdlAccounts to be defined") + } + + visited := make(map[*IdlAccounts]struct{}) + if err := checkForIdlAccountsCycle(env.IdlAccounts, visited); err != nil { + return nil, err + } + + var result interface{} + if env.IdlAccounts != nil { + result = map[string]interface{}{ + "accounts": env.IdlAccounts, + } + } else { + result = env.IdlAccount + } + + return json.Marshal(result) +} + +func checkForIdlAccountsCycle(acc *IdlAccounts, visited map[*IdlAccounts]struct{}) error { + if acc == nil { + return nil + } + + if _, exists := visited[acc]; exists { + return fmt.Errorf("cycle detected in IdlAccounts named %q", acc.Name) + } + visited[acc] = struct{}{} + + for _, item := range acc.Accounts { + if (item.IdlAccount == nil) == (item.IdlAccounts == nil) { + return fmt.Errorf("invalid nested structure: expected either IdlAccount or IdlAccounts to be defined") + } + if item.IdlAccounts != nil { + if err := checkForIdlAccountsCycle(item.IdlAccounts, visited); err != nil { + return err + } + } + } + return nil +} + +type IdlAccount struct { + Docs []string `json:"docs"` // @custom + Name string `json:"name"` + IsMut bool `json:"isMut"` + IsSigner bool `json:"isSigner"` + Optional bool `json:"optional"` // @custom +} + +// A nested/recursive version of IdlAccount. +type IdlAccounts struct { + Name string `json:"name"` + Docs []string `json:"docs"` // @custom + Accounts IdlAccountItemSlice `json:"accounts"` +} + +type IdlField struct { + Name string `json:"name"` + Docs []string `json:"docs"` // @custom + Type IdlType `json:"type"` +} + +// PDA is a struct that does not correlate to an official IDL type +// It is needed to encode seeds to calculate the address for PDA account reads +type PDATypeDef struct { + Prefix []byte `json:"prefix,omitempty"` + Seeds []PDASeed `json:"seeds,omitempty"` +} + +type PDASeed struct { + Name string `json:"name"` + Type IdlType `json:"type"` +} + +type IdlTypeAsString string + +const ( + IdlTypeBool IdlTypeAsString = "bool" + IdlTypeU8 IdlTypeAsString = "u8" + IdlTypeI8 IdlTypeAsString = "i8" + IdlTypeU16 IdlTypeAsString = "u16" + IdlTypeI16 IdlTypeAsString = "i16" + IdlTypeU32 IdlTypeAsString = "u32" + IdlTypeI32 IdlTypeAsString = "i32" + IdlTypeU64 IdlTypeAsString = "u64" + IdlTypeI64 IdlTypeAsString = "i64" + IdlTypeU128 IdlTypeAsString = "u128" + IdlTypeI128 IdlTypeAsString = "i128" + IdlTypeBytes IdlTypeAsString = "bytes" + IdlTypeString IdlTypeAsString = "string" + IdlTypePublicKey IdlTypeAsString = "publicKey" + + // Custom additions: + IdlTypeUnixTimestamp IdlTypeAsString = "unixTimestamp" + IdlTypeHash IdlTypeAsString = "hash" + IdlTypeDuration IdlTypeAsString = "duration" +) + +type IdlTypeVec struct { + Vec IdlType `json:"vec"` +} + +type IdlTypeOption struct { + Option IdlType `json:"option"` +} + +// User defined type. +type IdlTypeDefined struct { + Defined string `json:"defined"` +} + +// Wrapper type: +type IdlTypeArray struct { + Thing IdlType + Num int +} + +func (env IdlType) MarshalJSON() ([]byte, error) { + var result interface{} + switch { + case env.IsString(): + result = env.GetString() + case env.IsIdlTypeVec(): + result = env.GetIdlTypeVec() + case env.IsIdlTypeOption(): + result = env.GetIdlTypeOption() + case env.IsIdlTypeDefined(): + result = env.GetIdlTypeDefined() + case env.IsArray(): + array := env.GetArray() + result = map[string]interface{}{ + "array": []interface{}{array.Thing, array.Num}, + } + default: + return nil, fmt.Errorf("nil envelope is not supported in IdlType") + } + + return json.Marshal(result) +} + +func (env *IdlType) UnmarshalJSON(data []byte) error { + var temp interface{} + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + if temp == nil { + return fmt.Errorf("envelope is nil: %v", env) + } + + switch v := temp.(type) { + case string: + env.AsString = IdlTypeAsString(v) + case map[string]interface{}: + if len(v) == 0 { + return nil + } + + var typeFound bool + if _, ok := v["vec"]; ok { + var target IdlTypeVec + if err := utilz.TranscodeJSON(temp, &target); err != nil { + return err + } + typeFound = true + env.AsIdlTypeVec = &target + } + if _, ok := v["option"]; ok { + if typeFound { + return fmt.Errorf("multiple types found for IdlType: %s", spew.Sdump(temp)) + } + var target IdlTypeOption + if err := utilz.TranscodeJSON(temp, &target); err != nil { + return err + } + typeFound = true + env.asIdlTypeOption = &target + } + if _, ok := v["defined"]; ok { + if typeFound { + return fmt.Errorf("multiple types found for IdlType: %s", spew.Sdump(temp)) + } + var target IdlTypeDefined + if err := utilz.TranscodeJSON(temp, &target); err != nil { + return err + } + typeFound = true + env.AsIdlTypeDefined = &target + } + if got, ok := v["array"]; ok { + if typeFound { + return fmt.Errorf("multiple types found for IdlType: %s", spew.Sdump(temp)) + } + arrVal, ok := got.([]interface{}) + if !ok { + return fmt.Errorf("array is not in expected format: %s", spew.Sdump(got)) + } + if len(arrVal) != 2 { + return fmt.Errorf("array is not of expected length: %s", spew.Sdump(got)) + } + var target IdlTypeArray + if err := utilz.TranscodeJSON(arrVal[0], &target.Thing); err != nil { + return err + } + num, ok := arrVal[1].(float64) + if !ok { + return fmt.Errorf("value is unexpected type: %T, expected float64", arrVal[1]) + } + target.Num = int(num) + env.AsIdlTypeArray = &target + } + default: + return fmt.Errorf("Unknown kind: %s", spew.Sdump(temp)) + } + + return nil +} + +// Wrapper type: +type IdlType struct { + AsString IdlTypeAsString + AsIdlTypeVec *IdlTypeVec + asIdlTypeOption *IdlTypeOption + AsIdlTypeDefined *IdlTypeDefined + AsIdlTypeArray *IdlTypeArray +} + +func NewIdlStringType(asString IdlTypeAsString) IdlType { + return IdlType{ + AsString: asString, + } +} + +func (env *IdlType) IsString() bool { + return env.AsString != "" +} +func (env *IdlType) IsIdlTypeVec() bool { + return env.AsIdlTypeVec != nil +} +func (env *IdlType) IsIdlTypeOption() bool { + return env.asIdlTypeOption != nil +} +func (env *IdlType) IsIdlTypeDefined() bool { + return env.AsIdlTypeDefined != nil +} +func (env *IdlType) IsArray() bool { + return env.AsIdlTypeArray != nil +} + +// Getters: +func (env *IdlType) GetString() IdlTypeAsString { + return env.AsString +} +func (env *IdlType) GetIdlTypeVec() *IdlTypeVec { + return env.AsIdlTypeVec +} +func (env *IdlType) GetIdlTypeOption() *IdlTypeOption { + return env.asIdlTypeOption +} +func (env *IdlType) GetIdlTypeDefined() *IdlTypeDefined { + return env.AsIdlTypeDefined +} +func (env *IdlType) GetArray() *IdlTypeArray { + return env.AsIdlTypeArray +} + +type IdlTypeDef struct { + Name string `json:"name"` + Type IdlTypeDefTy `json:"type"` +} + +type IdlTypeDefTyKind string + +const ( + IdlTypeDefTyKindStruct IdlTypeDefTyKind = "struct" + IdlTypeDefTyKindEnum IdlTypeDefTyKind = "enum" + IdlTypeDefTyKindCustom IdlTypeDefTyKind = "custom" +) + +type IdlTypeDefTyStruct struct { + Kind IdlTypeDefTyKind `json:"kind"` // == "struct" + + Fields *IdlTypeDefStruct `json:"fields,omitempty"` +} + +type IdlTypeDefTyEnum struct { + Kind IdlTypeDefTyKind `json:"kind"` // == "enum" + + Variants IdlEnumVariantSlice `json:"variants,omitempty"` +} + +var NilIdlTypeDefTy = IdlTypeDef{Type: IdlTypeDefTy{ + Kind: "struct", + Fields: &IdlTypeDefStruct{}, +}} + +type IdlTypeDefTy struct { + Kind IdlTypeDefTyKind `json:"kind"` + + Fields *IdlTypeDefStruct `json:"fields,omitempty"` + Variants IdlEnumVariantSlice `json:"variants,omitempty"` + Codec string `json:"codec,omitempty"` +} + +type IdlEnumVariantSlice []IdlEnumVariant + +func (slice IdlEnumVariantSlice) IsAllUint8() bool { + for _, elem := range slice { + if !elem.IsUint8() { + return false + } + } + return true +} + +func (slice IdlEnumVariantSlice) IsSimpleEnum() bool { + return slice.IsAllUint8() +} + +type IdlTypeDefStruct = []IdlField + +type IdlEnumVariant struct { + Name string `json:"name"` + Docs []string `json:"docs"` // @custom + Fields *IdlEnumFields `json:"fields,omitempty"` +} + +func (variant *IdlEnumVariant) IsUint8() bool { + // it's a simple uint8 if there is no fields data + return variant.Fields == nil +} + +// type IdlEnumFields = IdlEnumFieldsNamed | IdlEnumFieldsTuple; +type IdlEnumFields struct { + IdlEnumFieldsNamed *IdlEnumFieldsNamed + IdlEnumFieldsTuple *IdlEnumFieldsTuple +} + +type IdlEnumFieldsNamed []IdlField + +type IdlEnumFieldsTuple []IdlType + +// TODO: verify with examples +func (env *IdlEnumFields) UnmarshalJSON(data []byte) error { + var temp any + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + if temp == nil { + return fmt.Errorf("envelope is nil: %v", env) + } + + switch v := temp.(type) { + case []any: + if len(v) == 0 { + return nil + } + + firstItem := v[0] + + if _, ok := firstItem.(map[string]any)["name"]; ok { + // TODO: + // If has `name` field, then it's most likely a IdlEnumFieldsNamed. + return utilz.TranscodeJSON(temp, &env.IdlEnumFieldsNamed) + } + return utilz.TranscodeJSON(temp, &env.IdlEnumFieldsTuple) + case map[string]any: + // Only one or the other field is set. Returning early is safe + if named, ok := v["IdlEnumFieldsNamed"]; ok { + return utilz.TranscodeJSON(named, &env.IdlEnumFieldsNamed) + } + if tuple, ok := v["IdlEnumFieldsTuple"]; ok { + return utilz.TranscodeJSON(tuple, &env.IdlEnumFieldsTuple) + } + return fmt.Errorf("Unknown type: %s", spew.Sdump(v)) + default: + return fmt.Errorf("Unknown kind: %s", spew.Sdump(temp)) + } +} + +type IdlErrorCode struct { + Code int `json:"code"` + Name string `json:"name"` + Msg string `json:"msg,omitempty"` +} diff --git a/pkg/types/solana/contract_reader.go b/pkg/types/solana/contract_reader.go new file mode 100644 index 000000000..c534f5715 --- /dev/null +++ b/pkg/types/solana/contract_reader.go @@ -0,0 +1,159 @@ +package solana + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type PollingFilter struct { + Retention *time.Duration `json:"retention,omitempty"` // maximum amount of time to retain logs + MaxLogsKept *int64 `json:"maxLogsKept,omitempty"` // maximum number of logs to retain ( 0 = unlimited ) + StartingBlock *int64 `json:"startingBlock,omitempty"` // which block to start looking for logs + IncludeReverted *bool `json:"includeReverted"` // whether to include logs emitted by transactions which failed while executing on chain +} + +type ContractReader struct { + Namespaces map[string]ChainContractReader `json:"namespaces"` + // AddressShareGroups lists namespaces groups that share the same address. + // Whichever namespace or i.e. Binding from the list is Bound first will share that address with the rest of the group. + // Namespaces that were bound after the first one still have to be Bound to be initialised. + // If they are Bound with an empty address string, they will use the address of the first Bound contract. + // If they are Bound with a non-empty address string, an error will be thrown unless the address matches the address of the first Bound shared contract. + AddressShareGroups [][]string `json:"addressShareGroups,omitempty"` +} + +type ChainContractReader struct { + IDL `json:"anchorIDL"` + *PollingFilter `json:"pollingFilter,omitempty"` + // Reads key is the off-chain name for this read. + Reads map[string]ReadDefinition `json:"reads"` +} + +type EventDefinitions struct { + IndexedField0 *IndexedField `json:"indexedField0"` + IndexedField1 *IndexedField `json:"indexedField1"` + IndexedField2 *IndexedField `json:"indexedField2"` + IndexedField3 *IndexedField `json:"indexedField3"` + // PollingFilter should be defined on a contract level in ContractPollingFilter, unless event needs to override the + // contract level filter options. + *PollingFilter `json:"pollingFilter,omitempty"` +} + +type MultiReader struct { + // Reads is a list of reads that is sequentially read to fill out a complete response for the parent read. + // Parent ReadDefinition has to define codec modifiers which adds fields that are to be filled out by the reads in Reads. + Reads []ReadDefinition `json:"reads,omitempty"` + // ReuseParams If true, params from parent read will be reused for all MultiReader Reads. + ReuseParams bool `json:"reuseParams"` +} + +type ReadDefinition struct { + ChainSpecificName string `json:"chainSpecificName"` + ReadType ReadType `json:"readType,omitempty"` + ErrOnMissingAccountData bool `json:"errOnMissingAccountData,omitempty"` + InputModifications codec.ModifiersConfig `json:"inputModifications,omitempty"` + OutputModifications codec.ModifiersConfig `json:"outputModifications,omitempty"` + PDADefinition PDATypeDef `json:"pdaDefinition,omitempty"` // Only used for PDA account reads + MultiReader *MultiReader `json:"multiReader,omitempty"` + EventDefinitions *EventDefinitions `json:"eventDefinitions,omitempty"` + // ResponseAddressHardCoder hardcodes the address of the contract into the defined field in the response. + ResponseAddressHardCoder *codec.HardCodeModifierConfig `json:"responseAddressHardCoder,omitempty"` +} + +func (d ReadDefinition) HasPollingFilter() bool { + return d.EventDefinitions != nil && d.EventDefinitions.PollingFilter != nil +} + +type ReadType int + +const ( + Account ReadType = iota + Event +) + +func (r ReadType) String() string { + switch r { + case Account: + return "Account" + case Event: + return "Event" + default: + return fmt.Sprintf("Unknown(%d)", r) + } +} + +func (c *ContractReader) UnmarshalJSON(bytes []byte) error { + rawJSON := make(map[string]json.RawMessage) + if err := json.Unmarshal(bytes, &rawJSON); err != nil { + return err + } + + c.Namespaces = make(map[string]ChainContractReader) + if err := json.Unmarshal(rawJSON["namespaces"], &c.Namespaces); err != nil { + return err + } + + if rawJSON["addressShareGroups"] != nil { + if err := json.Unmarshal(rawJSON["addressShareGroups"], &c.AddressShareGroups); err != nil { + return err + } + } + + if c.AddressShareGroups != nil { + seen := make(map[string][]string) + for _, group := range c.AddressShareGroups { + for _, namespace := range group { + if seenIn, alreadySeen := seen[namespace]; alreadySeen { + return fmt.Errorf("namespace %s is already in share group %v: %w", namespace, seenIn, commontypes.ErrInvalidConfig) + } + seen[namespace] = group + } + } + } + + return nil +} + +func (c *ChainContractReader) UnmarshalJSON(bytes []byte) error { + rawJSON := make(map[string]json.RawMessage) + if err := json.Unmarshal(bytes, &rawJSON); err != nil { + return err + } + + idlBytes := rawJSON["anchorIDL"] + var rawString string + if err := json.Unmarshal(idlBytes, &rawString); err == nil { + if err = json.Unmarshal([]byte(rawString), &c.IDL); err != nil { + return fmt.Errorf("failed to parse anchorIDL string as IDL struct: %w", err) + } + return nil + } + + // If we didn't get a string, attempt to parse directly as an IDL object + if err := json.Unmarshal(idlBytes, &c.IDL); err != nil { + return fmt.Errorf("anchorIDL field is neither a valid JSON string nor a valid IDL object: %w", err) + } + + if len(c.IDL.Accounts) == 0 && len(c.IDL.Events) == 0 { + return fmt.Errorf("namespace idl must have at least one account or event: %w", commontypes.ErrInvalidConfig) + } + + if err := json.Unmarshal(rawJSON["reads"], &c.Reads); err != nil { + return err + } + + if len(c.Reads) == 0 { + return fmt.Errorf("namespace must have at least one read: %w", commontypes.ErrInvalidConfig) + } + + return nil +} + +type IndexedField struct { + OffChainPath string `json:"offChainPath"` + OnChainPath string `json:"onChainPath"` +} diff --git a/pkg/types/solana/contract_writer.go b/pkg/types/solana/contract_writer.go new file mode 100644 index 000000000..221a96d7b --- /dev/null +++ b/pkg/types/solana/contract_writer.go @@ -0,0 +1,29 @@ +package solana + +import "github.com/smartcontractkit/chainlink-common/pkg/codec" + +// nolint // ignoring naming suggestion +type ContractWriterConfig struct { + Programs map[string]ProgramConfig `json:"programs"` +} + +type ProgramConfig struct { + Methods map[string]MethodConfig `json:"methods"` + IDL string `json:"idl"` +} + +type MethodConfig struct { + FromAddress string `json:"fromAddress"` + InputModifications codec.ModifiersConfig `json:"inputModifications,omitempty"` + ChainSpecificName string `json:"chainSpecificName"` + LookupTables LookupTables `json:"lookupTables,omitempty"` + Accounts []Lookup `json:"accounts"` + ATAs []ATALookup `json:"atas,omitempty"` + // Location in the args where the debug ID is stored + DebugIDLocation string `json:"debugIDLocation,omitempty"` + ArgsTransform string `json:"argsTransform,omitempty"` + // Overhead added to calculated compute units in the args transform + ComputeUnitLimitOverhead uint32 `json:"ComputeUnitLimitOverhead,omitempty"` + // Configs for buffering payloads to support larger transaction sizes for this method + BufferPayloadMethod string `json:"bufferPayloadMethod,omitempty"` +} diff --git a/pkg/types/solana/lookups.go b/pkg/types/solana/lookups.go new file mode 100644 index 000000000..0a78f33f4 --- /dev/null +++ b/pkg/types/solana/lookups.go @@ -0,0 +1,91 @@ +package solana + +type Lookup struct { + Optional bool + AccountConstant *AccountConstant `json:"accountConstant,omitempty"` + AccountLookup *AccountLookup `json:"accountLookup,omitempty"` + PDALookups *PDALookups `json:"pdas,omitempty"` + AccountsFromLookupTable *AccountsFromLookupTable `json:"accountsFromLookupTable,omitempty"` +} + +func (l Lookup) IsNil() bool { + return l.AccountConstant == nil && l.AccountLookup == nil && l.PDALookups == nil && l.AccountsFromLookupTable == nil +} + +// AccountConstant represents a fixed address, provided in Base58 format, converted into a `solana.PublicKey`. +type AccountConstant struct { + Name string `json:"name,omitempty"` + Address string `json:"address"` + IsSigner bool `json:"isSigner,omitempty"` + IsWritable bool `json:"isWritable,omitempty"` +} + +// AccountLookup dynamically derives an account address from args using a specified location path. +type AccountLookup struct { + Name string `json:"name,omitempty"` + Location string `json:"location"` + // IsSigner and IsWritable can either be a constant bool or a location to a bitmap which decides the bools + IsSigner MetaBool `json:"isSigner,omitempty"` + IsWritable MetaBool `json:"isWritable,omitempty"` +} + +type MetaBool struct { + Value bool `json:"value,omitempty"` // bool value + BitmapLocation string `json:"bitmapLocation,omitempty"` // dot separated location of the bitmap +} + +type Seed struct { + Static []byte `json:"static,omitempty"` // Static seed value + Dynamic Lookup `json:"dynamic,omitempty"` // Dynamic lookup for seed +} + +// PDALookups generates Program Derived Addresses (PDA) by combining a derived public key with one or more seeds. +type PDALookups struct { + Name string `json:"name,omitempty"` + // The public key of the PDA to be combined with seeds. If there are multiple PublicKeys + // there will be multiple PDAs generated by combining each PublicKey with the seeds. + PublicKey Lookup `json:"publicKey"` + // Seeds to be derived from an additional lookup + Seeds []Seed `json:"seeds"` + IsSigner bool `json:"isSigner,omitempty"` + IsWritable bool `json:"isWritable,omitempty"` + // OPTIONAL: On-chain location and type of desired data from PDA (e.g. a sub-account of the data account) + InternalField InternalField `json:"internalField,omitempty"` +} + +type InternalField struct { + // must map directly to IDL type + TypeName string `json:"typeName"` + Location string `json:"location"` + IDL string `json:"idl"` +} + +// LookupTables represents a list of lookup tables that are used to derive addresses for a program. +type LookupTables struct { + DerivedLookupTables []DerivedLookupTable `json:"derivedLookupTables,omitempty"` + StaticLookupTables [][32]byte `json:"staticLookupTables,omitempty"` // solana.PublicKey +} + +// DerivedLookupTable represents a lookup table that is used to derive addresses for a program. +type DerivedLookupTable struct { + Name string `json:"name,omitempty"` + Accounts Lookup `json:"accounts"` + Optional bool `json:"optional"` +} + +// AccountsFromLookupTable extracts accounts from a lookup table that was previously read and stored in memory. +type AccountsFromLookupTable struct { + LookupTableName string `json:"lookupTableName"` + IncludeIndexes []int `json:"includeIndexes"` +} + +type ATALookup struct { + // Field that determines whether the ATA lookup is necessary. Basically + // just need to check this field exists. Dot separated location. + Location string + // If the field exists, initialize a ATA account using the Wallet, Token Program, and Mint addresses below + WalletAddress Lookup + TokenProgram Lookup // Deprecated: The token program is now fetched from the mint account + MintAddress Lookup + Optional bool +}