diff --git a/cre-reliability/PoR/README.md b/cre-reliability/PoR/README.md new file mode 100644 index 00000000..f87a10a2 --- /dev/null +++ b/cre-reliability/PoR/README.md @@ -0,0 +1,22 @@ +# Blank Workflow Example + +This template provides a blank workflow example. It aims to give a starting point for writing a workflow from scratch and to get started with local simulation. + +Steps to run the example + +## 1. Update .env file + +You need to add a private key to env file. This is specifically required if you want to simulate chain writes. For that to work the key should be valid and funded. +If your workflow does not do any chain write then you can just put any dummy key as a private key. e.g. +``` +CRE_ETH_PRIVATE_KEY=0000000000000000000000000000000000000000000000000000000000000001 +``` + +## 2. Simulate the workflow +Run the command from project root directory + +```bash +cre workflow simulate --target local-simulation +``` + +It is recommended to look into other existing examples to see how to write a workflow. You can generate then by running the `cre init` command. diff --git a/cre-reliability/PoR/config.json b/cre-reliability/PoR/config.json new file mode 100644 index 00000000..2ca591fe --- /dev/null +++ b/cre-reliability/PoR/config.json @@ -0,0 +1,9 @@ +{ + "schedule": "0 */5 * * * *", + "url": "https://api.real-time-reserves.verinumus.io/v1/chainlink/proof-of-reserves/TrueUSD", + "balance_reader_address": "0xfab1d2A09F52cE3e03bEc75073B4f5d74D3e59B0", + "address_one": "0x13CB6AE34A13a0977F4d7101eBc24B87Bb23F0d5", + "address_two": "0xDc58480363fca702ADbECD61911314E602D324EA", + "data_feeds_cache_address": "0x220F3509213c61959e727a8c6493E0ED27966F8B", + "feed_id": "0x018e16c38e0003200000000000000000" +} diff --git a/cre-reliability/PoR/main.go b/cre-reliability/PoR/main.go new file mode 100644 index 00000000..eabbae2b --- /dev/null +++ b/cre-reliability/PoR/main.go @@ -0,0 +1,326 @@ +//go:build wasip1 + +package main + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "log/slog" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + chain_selectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk" + "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/balance_reader" + "github.com/smartcontractkit/chainlink-protos/cre/go/values" + "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/evm" + "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" +) + +type Config struct { + Schedule string `json:"schedule"` + URL string `json:"url"` + BalanceReaderAddress string `json:"balance_reader_address"` + AddressOne string `json:"address_one"` + AddressTwo string `json:"address_two"` + DataFeedsCacheAddress string `json:"data_feeds_cache_address"` + FeedID string `json:"feed_id"` +} + +func RunProofOfReservesWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { + return cre.Workflow[*Config]{ + cre.Handler( + cron.Trigger(&cron.Config{Schedule: config.Schedule}), + onTrigger, + ), + }, nil +} + +func onTrigger(config *Config, runtime cre.Runtime, payload *cron.Payload) (string, error) { + runtime.Logger().Info("PoR workflow started", "payload", payload) + + if config.Schedule == "" { + runtime.Logger().Error("config value 'schedule' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'schedule' cannot be empty") + } + if config.URL == "" { + runtime.Logger().Error("config value 'url' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'url' cannot be empty") + } + if config.BalanceReaderAddress == "" { + runtime.Logger().Error("config value 'balance_reader_address' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'balance_reader_address' cannot be empty") + } + if config.AddressOne == "" { + runtime.Logger().Error("config value 'address_one' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'address_one' cannot be empty") + } + if config.AddressTwo == "" { + runtime.Logger().Error("config value 'address_two' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'address_two' cannot be empty") + } + if config.DataFeedsCacheAddress == "" { + runtime.Logger().Error("config value 'data_feeds_cache_address' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'data_feeds_cache_address' cannot be empty") + } + if config.FeedID == "" { + runtime.Logger().Error("config value 'feed_id' cannot be empty", "config", config) + return "", fmt.Errorf("config value 'feed_id' cannot be empty") + } + + // get balance with BalanceAt() + evmClient := evm.Client{ChainSelector: chain_selectors.ETHEREUM_TESTNET_SEPOLIA.Selector} + runtime.Logger().Info("Got EVM client", "chainSelector", evmClient.ChainSelector) + + // For testing purposes, there is no handling of index out of range or nil cases. + // It allows for the configuration of empty addresses, a single address, or zero balances. + // The happy-path scenario in the system tests guarantees there are at least two addresses present. + // However, in real-world usage, it is advisable to implement + // proper validation for the configuration and handle possible errors. + addressToRead1 := common.HexToAddress(config.AddressOne) + balanceAtOutput, err := evmClient.BalanceAt(runtime, &evm.BalanceAtRequest{ + Account: addressToRead1.Bytes(), + BlockNumber: nil, + }).Await() + if err != nil { + runtime.Logger().Error(fmt.Sprintf("[logger] failed to get on-chain balance: %v", err)) + return "", fmt.Errorf("failed to get on-chain balance: %w", err) + } + runtime.Logger().With().Info(fmt.Sprintf("[logger] Got on-chain balance with BalanceAt() for address %s: %s", addressToRead1, balanceAtOutput.Balance.String())) + // Convert protobuf BigInt to big.Int manually to avoid import conflicts + balanceAtResult := values.ProtoToBigInt(balanceAtOutput.Balance) + runtime.Logger().With().Info(fmt.Sprintf("[logger] Got on-chain balance with BalanceAt() for address %s: %s", addressToRead1, balanceAtResult.String())) + + // get balance with CallContract + readBalancesParsedABI, err := getReadBalancesContractABI(runtime) + if err != nil { + runtime.Logger().Error(fmt.Sprintf("failed to get ReadBalances ABI: %v", err)) + return "", fmt.Errorf("failed to get ReadBalances ABI: %w", err) + } + + // To test that reading the contract is operational, it is sufficient to use 1 address. + // For testing purposes, there is no index out of range or nil handling, + // see comments above for more details (TL:DR; implement your own proper validation) + addressToRead2 := common.HexToAddress(config.AddressTwo) + readBalancesOutput, err := readBalancesFromContract([]common.Address{addressToRead2}, readBalancesParsedABI, evmClient, runtime, config) + if err != nil { + runtime.Logger().Error(fmt.Sprintf("failed to read balances from contract: %v", err)) + return "", fmt.Errorf("failed to read balances from contract: %w", err) + } + + var readBalancePrices []*big.Int + methodName := "getNativeBalances" + err = readBalancesParsedABI.UnpackIntoInterface(&readBalancePrices, methodName, readBalancesOutput.Data) + if err != nil { + runtime.Logger().Error(fmt.Sprintf("failed to read CallContract output: %v", err)) + return "", fmt.Errorf("failed to read CallContract output: %w", err) + } + runtime.Logger().With().Info(fmt.Sprintf("Read on-onchain balances for address %v: %v", addressToRead2.String(), &readBalancePrices)) + + // get total on-chain balance + allOnchainBalances := append(readBalancePrices, balanceAtResult) + var totalOnChainBalance big.Int + for _, balance := range allOnchainBalances { + totalOnChainBalance = *totalOnChainBalance.Add(&totalOnChainBalance, balance) + } + runtime.Logger().With().Info(fmt.Sprintf("Total on-chain balance for addresses %v", &totalOnChainBalance)) + + totalPriceOutput, err := cre.RunInNodeMode(config, runtime, + func(config *Config, nodeRuntime cre.NodeRuntime) (priceOutput, error) { + httpOutput, err := getHTTPPrice(config, nodeRuntime) + if err != nil { + return priceOutput{}, fmt.Errorf("failed to get HTTP price: %w", err) + } + httpOutput.Price.Add(httpOutput.Price, &totalOnChainBalance) + return httpOutput, nil + }, + cre.ConsensusIdenticalAggregation[priceOutput](), + ).Await() + if err != nil { + return "", fmt.Errorf("failed to get price: %w", err) + } + runtime.Logger().With().Info(fmt.Sprintf("Got price: %s, for feed: %s, at time: %d", totalPriceOutput.Price.String(), common.Bytes2Hex(totalPriceOutput.FeedID[:]), totalPriceOutput.Timestamp)) + + encodedPrice, err := encodeReports([]priceOutput{totalPriceOutput}) + if err != nil { + return "", fmt.Errorf("failed to pack price report: %w", err) + } + + report, err := runtime.GenerateReport(&cre.ReportRequest{ + EncodedPayload: encodedPrice, + EncoderName: "evm", + SigningAlgo: "ecdsa", + HashingAlgo: "keccak256", + }).Await() + if err != nil { + return "", fmt.Errorf("failed to generate report: %w", err) + } + runtime.Logger().With().Info(fmt.Sprintln("final report generated")) + + receiver, err := common.ParseHexOrString(config.DataFeedsCacheAddress) + if err != nil { + return "", fmt.Errorf("failed to decode hex string: %w", err) + } + wrOutput, err := evmClient.WriteReport(runtime, &evm.WriteCreReportRequest{ + Receiver: receiver, + Report: report, + GasConfig: &evm.GasConfig{GasLimit: 5000000}, + }).Await() + if err != nil { + runtime.Logger().Error(fmt.Sprintf("[logger] failed to write report on-chain: %v", err)) + return "", fmt.Errorf("failed to write report on-chain: %w", err) + } + runtime.Logger().With().Info("Submitted report on-chain") + + var message = "PoR Workflow successfully completed" + if wrOutput.ErrorMessage != nil { + message = *wrOutput.ErrorMessage + } + + return message, nil +} + +func getReadBalancesContractABI(runtime cre.Runtime) (*abi.ABI, error) { + runtime.Logger().Info("getting Balance Reader contract ABI") + readBalancesABI, abiErr := balance_reader.BalanceReaderMetaData.GetAbi() + if abiErr != nil { + runtime.Logger().Error("failed to get Balance Reader contract ABI", "error", abiErr) + return nil, fmt.Errorf("failed to get Balance Reader contract ABI: %w", abiErr) + } + runtime.Logger().Info("successfully got Balance Reader contract ABI") + return readBalancesABI, nil +} + +func readBalancesFromContract(addresses []common.Address, readBalancesABI *abi.ABI, evmClient evm.Client, runtime cre.Runtime, config *Config) (*evm.CallContractReply, error) { + methodName := "getNativeBalances" + packedData, err := readBalancesABI.Pack(methodName, addresses) + if err != nil { + runtime.Logger().Error(fmt.Sprintf("failed to pack read balances call: %v", err)) + return nil, fmt.Errorf("failed to pack read balances call: %w", err) + } + readBalancesOutput, err := evmClient.CallContract(runtime, &evm.CallContractRequest{ + Call: &evm.CallMsg{ + To: common.HexToAddress(config.BalanceReaderAddress).Bytes(), + Data: packedData, + }, + }).Await() + if err != nil { + runtime.Logger().Error(fmt.Sprintf("[logger] failed to get balances %v: %v", addresses, err)) + return nil, fmt.Errorf("failed to get balances for addresses %v: %w", addresses, err) + } + runtime.Logger().With().Info(fmt.Sprintf("Got raw CallContract output: %s", hex.EncodeToString(readBalancesOutput.Data))) + return readBalancesOutput, nil +} + +func main() { + wasm.NewRunner(func(configBytes []byte) (*Config, error) { + cfg := Config{} + if err := json.Unmarshal(configBytes, &cfg); err != nil { + return &Config{}, fmt.Errorf("failed to unmarshal config: %w", err) + } + + return &cfg, nil + }).Run(RunProofOfReservesWorkflow) +} + +type priceOutput struct { + FeedID [32]byte + Timestamp uint32 + Price *big.Int +} + +type PORResponse struct { + AccountName string `json:"accountName"` + TotalTrust float64 `json:"totalTrust"` + TotalToken float64 `json:"totalToken"` + Ripcord bool `json:"ripcord"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func getHTTPPrice(config *Config, runtime cre.NodeRuntime) (priceOutput, error) { + httpClient := &http.Client{} + + feedID, err := convertFeedIDtoBytes(config.FeedID) + if err != nil { + return priceOutput{}, fmt.Errorf("cannot convert feedID to bytes : %w : %b", err, feedID) + } + + fetchRequest := http.Request{ + Method: "GET", + Url: config.URL, + } + + r, err := httpClient.SendRequest(runtime, &fetchRequest).Await() + if err != nil { + return priceOutput{}, fmt.Errorf("failed to await price response from %s and %v err: %w", fetchRequest.String(), fetchRequest.Headers, err) + } + + var resp PORResponse + if err = json.Unmarshal(r.Body, &resp); err != nil { + return priceOutput{}, fmt.Errorf("failed to unmarshal price response: %w", err) + } + + runtime.Logger().With().Info(fmt.Sprintf("Response is account name: %s, totalTrust: %.10f, ripcord: %v, updatedAt: %s", resp.AccountName, resp.TotalTrust, resp.Ripcord, resp.UpdatedAt.String())) + + if resp.Ripcord { + runtime.Logger().With( + "feedID", config.FeedID, + ).Info(fmt.Sprintf("ripcord flag set for feed ID %s", config.FeedID)) + return priceOutput{}, sdk.BreakErr + } + + return priceOutput{ + FeedID: feedID, // TrueUSD + Timestamp: uint32(resp.UpdatedAt.Unix()), + Price: big.NewInt(int64(resp.TotalTrust * 100)), // Convert to integer cents + }, nil +} + +func convertFeedIDtoBytes(feedIDStr string) ([32]byte, error) { + if feedIDStr == "" { + return [32]byte{}, fmt.Errorf("feedID string is empty") + } + + if len(feedIDStr) < 2 { + return [32]byte{}, fmt.Errorf("feedID string too short: %q", feedIDStr) + } + + b, err := hex.DecodeString(feedIDStr[2:]) + if err != nil { + return [32]byte{}, err + } + + if len(b) < 32 { + nb := [32]byte{} + copy(nb[:], b[:]) + return nb, err + } + + return [32]byte(b), nil +} + +func encodeReports(reports []priceOutput) ([]byte, error) { + typ, err := abi.NewType("tuple[]", "", + []abi.ArgumentMarshaling{ + {Name: "FeedID", Type: "bytes32"}, + {Name: "Timestamp", Type: "uint32"}, + {Name: "Price", Type: "uint224"}, + }) + if err != nil { + return nil, fmt.Errorf("failed to create ABI type: %w", err) + } + + args := abi.Arguments{ + { + Name: "Reports", + Type: typ, + }, + } + return args.Pack(reports) +} diff --git a/cre-reliability/PoR/workflow.yaml b/cre-reliability/PoR/workflow.yaml new file mode 100644 index 00000000..e6f5a539 --- /dev/null +++ b/cre-reliability/PoR/workflow.yaml @@ -0,0 +1,34 @@ +# ========================================================================== +# CRE WORKFLOW SETTINGS FILE +# ========================================================================== +# Workflow-specific settings for CRE CLI targets. +# Each target defines user-workflow and workflow-artifacts groups. +# Settings here override CRE Project Settings File values. +# +# Example custom target: +# my-target: +# user-workflow: +# workflow-name: "MyExampleWorkflow" # Required: Workflow Registry name +# workflow-artifacts: +# workflow-path: "./main.ts" # Path to workflow entry point +# config-path: "./config.yaml" # Path to config file +# secrets-path: "../secrets.yaml" # Path to secrets file (project root by default) + +# ========================================================================== +local-simulation: + user-workflow: + workflow-name: "PoR" + workflow-artifacts: + workflow-path: "." + config-path: "./config.json" + secrets-path: "../secrets.yaml" + +# ========================================================================== +staging: + user-workflow: + workflow-name: "PoR" + workflow-artifacts: + workflow-path: "." + config-path: "./config.json" + secrets-path: "../secrets.yaml" + \ No newline at end of file diff --git a/cre-reliability/PoR_ts/bun.lock b/cre-reliability/PoR_ts/bun.lock new file mode 100644 index 00000000..66984ce3 --- /dev/null +++ b/cre-reliability/PoR_ts/bun.lock @@ -0,0 +1,77 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "por_ts", + "dependencies": { + "@chainlink/cre-sdk": "0.0.8-alpha", + "viem": "2.34.0", + "zod": "3.25.76", + }, + "devDependencies": { + "@types/bun": "1.2.21", + }, + }, + }, + "packages": { + "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="], + + "@bufbuild/protobuf": ["@bufbuild/protobuf@2.6.3", "", {}, "sha512-w/gJKME9mYN7ZoUAmSMAWXk4hkVpxRKvEJCb3dV5g9wwWdxTJJ0ayOJAVcNxtdqaxDyFuC0uz4RSGVacJ030PQ=="], + + "@bufbuild/protoc-gen-es": ["@bufbuild/protoc-gen-es@2.6.3", "", { "dependencies": { "@bufbuild/protobuf": "2.6.3", "@bufbuild/protoplugin": "2.6.3" }, "peerDependencies": { "@bufbuild/protobuf": "2.6.3" }, "bin": { "protoc-gen-es": "bin/protoc-gen-es" } }, "sha512-20o4U/Th0yLK/ayQGJ8hwh+fmcI/2PWZFkTS4gv08AtOx31YA05/X/wbn+pLZLJCDP2ik4KTIWuV1j4gERs15A=="], + + "@bufbuild/protoplugin": ["@bufbuild/protoplugin@2.6.3", "", { "dependencies": { "@bufbuild/protobuf": "2.6.3", "@typescript/vfs": "^1.5.2", "typescript": "5.4.5" } }, "sha512-VceMuxeRukxGeABfo34SXq0VqY1MU+mzS+PBf0HAWo97ylFut8F6sQ3mV0tKiM08UQ/xQco7lxCn83BkoxrWrA=="], + + "@chainlink/cre-sdk": ["@chainlink/cre-sdk@0.0.8-alpha", "", { "dependencies": { "@bufbuild/protobuf": "2.6.3", "@bufbuild/protoc-gen-es": "2.6.3", "@chainlink/cre-sdk-javy-plugin": "0.0.6-alpha", "@standard-schema/spec": "1.0.0", "viem": "2.34.0", "zod": "3.25.76" }, "bin": { "cre-compile": "bin/cre-compile.ts" } }, "sha512-lL+uE7LTn+PHEw5ciFMR6I5T3PUsZY3x7JX2L3w5+AAGC1kj/f59I2WHw7AGbo4VXS0c80MiKbuU8PVKMNPKrg=="], + + "@chainlink/cre-sdk-javy-plugin": ["@chainlink/cre-sdk-javy-plugin@0.0.6-alpha", "", { "bin": { "cre-compile-workflow": "bin/compile-workflow.ts", "cre-setup": "bin/setup.ts" } }, "sha512-iSHCeQVJpAiZ4rO0yR9QRb0dkqnBYGx515k745nGroexYri8MzYsh1qfr9w1XTxEdvWBBYOv6rNzq8bel/NvKg=="], + + "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], + + "@noble/curves": ["@noble/curves@1.9.6", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], + + "@scure/bip32": ["@scure/bip32@1.7.0", "", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], + + "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + + "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], + + "@types/node": ["@types/node@24.9.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg=="], + + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + + "@typescript/vfs": ["@typescript/vfs@1.6.2", "", { "dependencies": { "debug": "^4.1.1" }, "peerDependencies": { "typescript": "*" } }, "sha512-hoBwJwcbKHmvd2QVebiytN1aELvpk9B74B4L1mFm/XT1Q/VOYAWl2vQ9AWRFtQq8zmz6enTpfTV8WRc4ATjW/g=="], + + "abitype": ["abitype@1.0.8", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3 >=3.22.0" } }, "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg=="], + + "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + + "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "ox": ["ox@0.8.7", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "^1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.8", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" } }, "sha512-W1f0FiMf9NZqtHPEDEAEkyzZDwbIKfmH2qmQx8NNiQ/9JhxrSblmtLJsSfTtQG5YKowLOnBlLVguCyxm/7ztxw=="], + + "typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "viem": ["viem@2.34.0", "", { "dependencies": { "@noble/curves": "1.9.6", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.0.8", "isows": "1.0.7", "ox": "0.8.7", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" } }, "sha512-HJZG9Wt0DLX042MG0PK17tpataxtdAEhpta9/Q44FqKwy3xZMI5Lx4jF+zZPuXFuYjZ68R0PXqRwlswHs6r4gA=="], + + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + } +} diff --git a/cre-reliability/PoR_ts/config.json b/cre-reliability/PoR_ts/config.json new file mode 100644 index 00000000..7c5a040e --- /dev/null +++ b/cre-reliability/PoR_ts/config.json @@ -0,0 +1,9 @@ +{ + "schedule": "0 */5 * * * *", + "url": "https://api.real-time-reserves.verinumus.io/v1/chainlink/proof-of-reserves/TrueUSD", + "balance_reader_address": "0xfab1d2A09F52cE3e03bEc75073B4f5d74D3e59B0", + "address_one": "0x13CB6AE34A13a0977F4d7101eBc24B87Bb23F0d5", + "address_two": "0xDc58480363fca702ADbECD61911314E602D324EA", + "data_feeds_cache_address": "0x220F3509213c61959e727a8c6493E0ED27966F8B", + "feed_id": "0x018e16c38e000310000000000000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/cre-reliability/PoR_ts/contracts/BalanceReader.ts b/cre-reliability/PoR_ts/contracts/BalanceReader.ts new file mode 100644 index 00000000..2cb90454 --- /dev/null +++ b/cre-reliability/PoR_ts/contracts/BalanceReader.ts @@ -0,0 +1,16 @@ +export const BalanceReader = [ + { + inputs: [{ internalType: 'address[]', name: 'addresses', type: 'address[]' }], + name: 'getNativeBalances', + outputs: [{ internalType: 'uint256[]', name: '', type: 'uint256[]' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'typeAndVersion', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function', + }, +] as const diff --git a/cre-reliability/PoR_ts/main.ts b/cre-reliability/PoR_ts/main.ts new file mode 100644 index 00000000..d35a3dd6 --- /dev/null +++ b/cre-reliability/PoR_ts/main.ts @@ -0,0 +1,254 @@ +import { + bytesToHex, + ConsensusAggregationByFields, + type CronPayload, + cre, + encodeCallMsg, + type HTTPSendRequester, + hexToBase64, + hexToBytes, + LAST_FINALIZED_BLOCK_NUMBER, + median, + type EVMClient, + Runner, + type Runtime, + TxStatus, +} from '@chainlink/cre-sdk' +import {Abi, type Address, decodeFunctionResult, encodeAbiParameters,encodePacked,encodeFunctionData, Hex, zeroAddress} from 'viem' +import { z } from 'zod' +import { BalanceReader} from './contracts/BalanceReader' +import { + BalanceAtReply, + BalanceAtRequest +} from "@chainlink/cre-sdk/dist/generated/capabilities/blockchain/evm/v1alpha/client_pb"; + +type PriceOutput = { + feedId: string; // string + timestamp: number; // uint32 + price: bigint; // uint224 +}; + +type PORResponse = { + accountName: string; + totalTrust: number; // float + totalToken: number; + ripcord: boolean; + updatedAt: string; // ISO +}; + +type TupleArrayReport = [Hex, number, BigInt][] + +const onCronTrigger = (runtime: Runtime, payload: CronPayload): string => { + let cfg:Config = runtime.config + runtime.log("PoR_ts workflow started" + JSON.stringify(cfg)); + + // Validate config (match Go’s checks) + assertNonEmpty(cfg.schedule, "schedule", runtime); + assertNonEmpty(cfg.url, "url", runtime); + assertNonEmpty(cfg.balance_reader_address, "balance_reader_address", runtime); + assertNonEmpty(cfg.address_one, "address_one", runtime); + assertNonEmpty(cfg.address_two, "address_two", runtime); + assertNonEmpty(cfg.data_feeds_cache_address, "data_feeds_cache_address", runtime); + assertNonEmpty(cfg.feed_id, "feed_id", runtime); + + runtime.log("Config is valid") + + // Read balance #1 via eth_getBalance equivalent + let evmClient = new cre.capabilities.EVMClient(BigInt("16015286601757825753")) + + runtime.log("evmClient created") + + let addressOneBalanceAtRequest:BalanceAtRequest={ + $typeName: "capabilities.blockchain.evm.v1alpha.BalanceAtRequest", + account:hexToBytes(cfg.address_one), + } + let balanceAddressOne:BalanceAtReply = evmClient.balanceAt(runtime,addressOneBalanceAtRequest).result() + // @ts-ignore + runtime.log(`Got on-chain balance with BalanceAt() address: ${cfg.address_one} balance: ${balanceAddressOne.balance.toString()}` ); + + // Read balance #2 via contract call: BalanceReader.getNativeBalances(address[]) + const callData = encodeFunctionData({ + abi: BalanceReader, + functionName: 'getNativeBalances', + args: [[cfg.address_two as Address]], + }) + + const contractCall = evmClient + .callContract(runtime, { + call: encodeCallMsg({ + from: zeroAddress, + to: cfg.balance_reader_address as Address, + data: callData, + }), + blockNumber: LAST_FINALIZED_BLOCK_NUMBER, + }) + .result() + runtime.log(`Got raw CallContract output: ${bytesToHex(contractCall.data)}`); + + + // Decode the result + const balances = decodeFunctionResult({ + abi: BalanceReader, + functionName: 'getNativeBalances', + data: bytesToHex(contractCall.data), + }) + + if (!balances || balances.length === 0) { + throw new Error('No balances returned from contract') + } + + const balances2:BigInt = balances[0] + runtime.log(`Read on-chain balances (contract) from ${cfg.address_two} value:${balances2.toString()}`); + + const httpPrice = getHTTPPrice(cfg, runtime); + + runtime.log("Encoding report data") + // Encode reports (tuple[] of (bytes32,uint32,uint224)) + const encoded = encodeReports(httpPrice,runtime); + + runtime.log("Encoding report") + // Generate & write report on-chain + const report = runtime.report({ + encodedPayload: hexToBase64(encoded), + encoderName:'evm', + signingAlgo: 'ecdsa', + hashingAlgo: 'keccak256', + }).result(); + + runtime.log("Writing report") + const resp = evmClient + .writeReport(runtime, { + receiver: cfg.data_feeds_cache_address, + report: report, + gasConfig: { + gasLimit: "5000000", + }, + }) + .result() + + const txStatus = resp.txStatus + + if (txStatus !== TxStatus.SUCCESS) { + throw new Error(`Failed to write report: ${resp.errorMessage || txStatus}`) + } + + const txHash = resp.txHash || new Uint8Array(32) + + runtime.log(`Write report transaction succeeded at txHash: ${bytesToHex(txHash)}`) + + return txHash.toString() +} + + +function getHTTPPrice(cfg: Config,runtime:Runtime): PriceOutput { + const httpCapability = new cre.capabilities.HTTPClient() + + const reserveInfo = httpCapability + .sendRequest( + runtime, + fetchReserveInfo, + ConsensusAggregationByFields({ + lastUpdated: median, + totalReserve: median, + }), + )(runtime.config) + .result() + + runtime.log(`ReserveInfo ${safeJsonStringify(reserveInfo)}`) + + return { feedId: cfg.feed_id , timestamp: Math.floor(reserveInfo.lastUpdated.getTime()/1000) , price: BigInt(reserveInfo.totalReserve * 1e18) }; +} + +const safeJsonStringify = (obj: any): string => + JSON.stringify(obj, (_, value) => (typeof value === 'bigint' ? value.toString() : value), 2) + +interface ReserveInfo { + lastUpdated: Date + totalReserve: number +} + +const fetchReserveInfo = (sendRequester: HTTPSendRequester, config: Config): ReserveInfo => { + const response = sendRequester.sendRequest({ url: config.url, method:"GET" }).result() + + + if (response.statusCode !== 200) { + throw new Error(`HTTP request failed with status: ${response.statusCode}`) + } + + const responseText = Buffer.from(response.body).toString('utf-8') + const porResp: PORResponse = JSON.parse(responseText) + + if (porResp.ripcord) { + throw new Error('ripcord is true') + } + + return { + lastUpdated: new Date(porResp.updatedAt), + totalReserve: porResp.totalToken, + } +} + +function encodeReports(report: PriceOutput,runtime: Runtime): Hex { + // tuple[] (bytes32 FeedID, uint32 Timestamp, uint224 Price) + runtime.log(`Encoding ${report.feedId as Address} ${report.timestamp} ${report.price}`) + + let abiParameters = [ + { + type: "tuple[]", + components: [ + { type: "bytes32" }, + { type: "uint32" }, + { type: "uint224" }, + ] + }, + ] + let data: [Hex, number, BigInt][] = [[report.feedId as Address,report.timestamp,report.price]] + + let reps :Hex=encodeAbiParameters(abiParameters,[data]) + + runtime.log(`Encoding done ${reps}`) + return reps +} + + + +function assertNonEmpty(v: string, name: string, runtime: Runtime) { + if (!v || v.trim() === "") { + runtime.log(`config value '${name}' cannot be empty`); + throw new Error(`config value '${name}' cannot be empty`); + } +} + +const configSchema = z.object({ + schedule: z.string(), + url: z.string(), + balance_reader_address: z.string(), + address_one: z.string(), + address_two: z.string(), + data_feeds_cache_address: z.string(), + feed_id: z.string(), +}) +type Config = z.infer + +export async function main() { + const runner = await Runner.newRunner({ + configSchema, + }) + await runner.run(initWorkflow) +} + +const initWorkflow = (config: Config) => { + const cronTrigger = new cre.capabilities.CronCapability() + const cfg:Config = config + + return [ + cre.handler( + cronTrigger.trigger({ + schedule: config.schedule, + }), + onCronTrigger, + ), + ] +} + +main() \ No newline at end of file diff --git a/cre-reliability/PoR_ts/package.json b/cre-reliability/PoR_ts/package.json new file mode 100644 index 00000000..8ed654c0 --- /dev/null +++ b/cre-reliability/PoR_ts/package.json @@ -0,0 +1,21 @@ +{ + "name": "por_ts", + "version": "1.0.0", + "private": true, + "description": "", + "license": "UNLICENSED", + "author": "", + "type": "commonjs", + "main": "dist/main.js", + "scripts": { + "postinstall": "bunx cre-setup" + }, + "dependencies": { + "@chainlink/cre-sdk": "0.0.8-alpha", + "viem": "2.34.0", + "zod": "3.25.76" + }, + "devDependencies": { + "@types/bun": "1.2.21" + } +} diff --git a/cre-reliability/PoR_ts/tsconfig.json b/cre-reliability/PoR_ts/tsconfig.json new file mode 100644 index 00000000..6dbe5a47 --- /dev/null +++ b/cre-reliability/PoR_ts/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "commonjs", + "outDir": "./dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": [ + "main.ts" + ] +} diff --git a/cre-reliability/PoR_ts/workflow.yaml b/cre-reliability/PoR_ts/workflow.yaml new file mode 100644 index 00000000..2cce516b --- /dev/null +++ b/cre-reliability/PoR_ts/workflow.yaml @@ -0,0 +1,34 @@ +# ========================================================================== +# CRE WORKFLOW SETTINGS FILE +# ========================================================================== +# Workflow-specific settings for CRE CLI targets. +# Each target defines user-workflow and workflow-artifacts groups. +# Settings here override CRE Project Settings File values. +# +# Example custom target: +# my-target: +# user-workflow: +# workflow-name: "MyExampleWorkflow" # Required: Workflow Registry name +# workflow-artifacts: +# workflow-path: "./main.ts" # Path to workflow entry point +# config-path: "./config.yaml" # Path to config file +# secrets-path: "../secrets.yaml" # Path to secrets file (project root by default) + +# ========================================================================== +local-simulation: + user-workflow: + workflow-name: "PoR_ts" + workflow-artifacts: + workflow-path: "./main.ts" + config-path: "./config.json" + secrets-path: "../secrets.yaml" + +# ========================================================================== +staging: + user-workflow: + workflow-name: "PoR_ts" + workflow-artifacts: + workflow-path: "./main.ts" + config-path: "./config.json" + secrets-path: "../secrets.yaml" + \ No newline at end of file diff --git a/cre-reliability/contracts/evm/src/BalanceReader.sol b/cre-reliability/contracts/evm/src/BalanceReader.sol new file mode 100644 index 00000000..6ac21cc2 --- /dev/null +++ b/cre-reliability/contracts/evm/src/BalanceReader.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITypeAndVersion} from "./ITypeAndVersion.sol"; + +/// @notice BalanceReader is used to read native currency balances from one or more accounts +/// using a contract method instead of an RPC "eth_getBalance" call. +contract BalanceReader is ITypeAndVersion { + string public constant override typeAndVersion = "BalanceReader 1.0.0"; + + function getNativeBalances(address[] memory addresses) public view returns (uint256[] memory) { + uint256[] memory balances = new uint256[](addresses.length); + for (uint256 i = 0; i < addresses.length; ++i) { + balances[i] = addresses[i].balance; + } + return balances; + } +} \ No newline at end of file diff --git a/cre-reliability/contracts/evm/src/abi/BalanceReader.abi b/cre-reliability/contracts/evm/src/abi/BalanceReader.abi new file mode 100644 index 00000000..af8ee1b6 --- /dev/null +++ b/cre-reliability/contracts/evm/src/abi/BalanceReader.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"}],"name":"getNativeBalances","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/cre-reliability/contracts/evm/src/generated/balance_reader/BalanceReader_mock.go b/cre-reliability/contracts/evm/src/generated/balance_reader/BalanceReader_mock.go new file mode 100644 index 00000000..bcd0078c --- /dev/null +++ b/cre-reliability/contracts/evm/src/generated/balance_reader/BalanceReader_mock.go @@ -0,0 +1,80 @@ +// Code generated — DO NOT EDIT. + +//go:build !wasip1 + +package balance_reader + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + evmmock "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/evm/mock" +) + +var ( + _ = errors.New + _ = fmt.Errorf + _ = big.NewInt + _ = common.Big1 +) + +// BalanceReaderMock is a mock implementation of BalanceReader for testing. +type BalanceReaderMock struct { + GetNativeBalances func(GetNativeBalancesInput) ([]*big.Int, error) + TypeAndVersion func() (string, error) +} + +// NewBalanceReaderMock creates a new BalanceReaderMock for testing. +func NewBalanceReaderMock(address common.Address, clientMock *evmmock.ClientCapability) *BalanceReaderMock { + mock := &BalanceReaderMock{} + + codec, err := NewCodec() + if err != nil { + panic("failed to create codec for mock: " + err.Error()) + } + + abi := codec.(*Codec).abi + _ = abi + + funcMap := map[string]func([]byte) ([]byte, error){ + string(abi.Methods["getNativeBalances"].ID[:4]): func(payload []byte) ([]byte, error) { + if mock.GetNativeBalances == nil { + return nil, errors.New("getNativeBalances method not mocked") + } + inputs := abi.Methods["getNativeBalances"].Inputs + + values, err := inputs.Unpack(payload) + if err != nil { + return nil, errors.New("Failed to unpack payload") + } + if len(values) != 1 { + return nil, errors.New("expected 1 input value") + } + + args := GetNativeBalancesInput{ + Addresses: values[0].([]common.Address), + } + + result, err := mock.GetNativeBalances(args) + if err != nil { + return nil, err + } + return abi.Methods["getNativeBalances"].Outputs.Pack(result) + }, + string(abi.Methods["typeAndVersion"].ID[:4]): func(payload []byte) ([]byte, error) { + if mock.TypeAndVersion == nil { + return nil, errors.New("typeAndVersion method not mocked") + } + result, err := mock.TypeAndVersion() + if err != nil { + return nil, err + } + return abi.Methods["typeAndVersion"].Outputs.Pack(result) + }, + } + + evmmock.AddContractMock(address, clientMock, funcMap, nil) + return mock +} diff --git a/cre-reliability/go.mod b/cre-reliability/go.mod new file mode 100644 index 00000000..6a6ff3b2 --- /dev/null +++ b/cre-reliability/go.mod @@ -0,0 +1,63 @@ +module cre-reliability + +go 1.25.1 + +require ( + github.com/ethereum/go-ethereum v1.16.5 + github.com/smartcontractkit/chain-selectors v1.0.74 + github.com/smartcontractkit/chainlink-common v0.9.6 + github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251003122604-772b72191274 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250918131840-564fe2776a35 + github.com/smartcontractkit/cre-sdk-go v0.9.0 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/evm v0.9.0 + github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http v0.9.0 + github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.9.0 +) + +require ( + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.3 // indirect + github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/holiman/uint256 v1.3.2 // indirect + github.com/invopop/jsonschema v0.13.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358 // indirect + github.com/stretchr/testify v1.11.1 // indirect + github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.36.0 // indirect + google.golang.org/protobuf v1.36.7 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/cre-reliability/go.sum b/cre-reliability/go.sum new file mode 100644 index 00000000..4a5f8038 --- /dev/null +++ b/cre-reliability/go.sum @@ -0,0 +1,261 @@ +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= +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/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +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/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= +github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= +github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= +github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= +github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/ethereum/c-kzg-4844/v2 v2.1.3 h1:DQ21UU0VSsuGy8+pcMJHDS0CV1bKmJmxsJYK8l3MiLU= +github.com/ethereum/c-kzg-4844/v2 v2.1.3/go.mod h1:fyNcYI/yAuLWJxf4uzVtS8VDKeoAaRM8G/+ADz/pRdA= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= +github.com/ethereum/go-ethereum v1.16.5 h1:GZI995PZkzP7ySCxEFaOPzS8+bd8NldE//1qvQDQpe0= +github.com/ethereum/go-ethereum v1.16.5/go.mod h1:kId9vOtlYg3PZk9VwKbGlQmSACB5ESPTBGT+M9zjmok= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/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/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= +github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= +github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +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/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/smartcontractkit/chain-selectors v1.0.74 h1:X9eHWTJKMF31+sZzQZyVW3yvqkVHLTezJGiJfCLDe3A= +github.com/smartcontractkit/chain-selectors v1.0.74/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= +github.com/smartcontractkit/chainlink-common v0.9.6 h1:xE6x3kujV0NC7AMo/LdCszVTc2ZR9bQWOlZvYiYvuoY= +github.com/smartcontractkit/chainlink-common v0.9.6/go.mod h1:1r3aM96KHAESfnayJ3BTHCkP1qJS1BEG1r4czeoaXlA= +github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251003122604-772b72191274 h1:7vcazdecB5LjHJzhFoj4BfpkhFqv+fVPsNeuBSQVaSA= +github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251003122604-772b72191274/go.mod h1:oyfOm4k0uqmgZIfxk1elI/59B02shbbJQiiUdPdbMgI= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250918131840-564fe2776a35 h1:hhKdzgNZT+TnohlmJODtaxlSk+jyEO79YNe8zLFtp78= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20250918131840-564fe2776a35/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= +github.com/smartcontractkit/cre-sdk-go v0.9.0 h1:MDO9HFb4tjvu4mI4gKvdO+qXP1irULxhFwlTPVBytaM= +github.com/smartcontractkit/cre-sdk-go v0.9.0/go.mod h1:CQY8hCISjctPmt8ViDVgFm4vMGLs5fYI198QhkBS++Y= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/evm v0.9.0 h1:0ddtacyL1aAFxIolQnbysYlJKP9FOLJc1YRFS/Z9OJA= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/evm v0.9.0/go.mod h1:VVJ4mvA7wOU1Ic5b/vTaBMHEUysyxd0gdPPXkAu8CmY= +github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http v0.9.0 h1:VTLdU4nZJ9L+4X0ql20rxQ06dt572A2kmGG2nVHRgiI= +github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http v0.9.0/go.mod h1:M83m3FsM1uqVu06OO58mKUSZJjjH8OGJsmvFpFlRDxI= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.9.0 h1:BWqX7Cnd6VnhHEpjfrQGEajPtAwqH4MH0D7o3iEPvvU= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.9.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= +github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358 h1:+NVzR5LZVazRUunzVn34u+lwnpmn6NTVPCeZOVyQHLo= +github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/cre-reliability/project.yaml b/cre-reliability/project.yaml new file mode 100644 index 00000000..781f3d53 --- /dev/null +++ b/cre-reliability/project.yaml @@ -0,0 +1,32 @@ +# ========================================================================== +# CRE PROJECT SETTINGS FILE +# ========================================================================== +# Project-specific settings for CRE CLI targets. +# Each target defines cre-cli, account, and rpcs groups. +# +# Example custom target: +# my-target: +# cre-cli: +# don-family: "zone-a" # Required: Workflow DON Family +# account: +# workflow-owner-address: "0x123..." # Optional: Owner wallet/MSIG address (used for --unsigned transactions) +# rpcs: +# - chain-name: ethereum-mainnet # Required: Chain RPC endpoints +# url: "https://mainnet.infura.io/v3/KEY" + +# ========================================================================== +local-simulation: + rpcs: + - chain-name: ethereum-testnet-sepolia + url: https://rpcs.cldev.sh/ethereum/sepolia + +# ========================================================================== +staging: + cre-cli: + don-family: "reliability" + account: + workflow-owner-address: "0xaA5CB7ef1eF5D54246e2d8Bd72125e422Dc3729F" + rpcs: + - chain-name: ethereum-testnet-sepolia + url: https://rpcs.cldev.sh/ethereum/sepolia + diff --git a/cre-reliability/secrets.yaml b/cre-reliability/secrets.yaml new file mode 100644 index 00000000..67e4e027 --- /dev/null +++ b/cre-reliability/secrets.yaml @@ -0,0 +1 @@ +secretsNames: \ No newline at end of file diff --git a/test/test_project/por_workflow/main.go b/test/test_project/por_workflow/main.go index e3b472fb..430672c7 100644 --- a/test/test_project/por_workflow/main.go +++ b/test/test_project/por_workflow/main.go @@ -3,26 +3,11 @@ package main import ( - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "log/slog" - "math/big" "time" - "por_workflow/contracts/evm/src/generated/balance_reader" - "por_workflow/contracts/evm/src/generated/ierc20" - "por_workflow/contracts/evm/src/generated/reserve_manager" - - "github.com/ethereum/go-ethereum/common" "github.com/shopspring/decimal" "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/evm" - "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http" - "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" - "github.com/smartcontractkit/cre-sdk-go/cre" - "github.com/smartcontractkit/cre-sdk-go/cre/wasm" ) // EVMConfig holds per-chain configuration.