From f97b8f94243436fad97dd6c3b7e09cf77d271c78 Mon Sep 17 00:00:00 2001 From: Skipper Date: Fri, 26 Jun 2026 12:09:37 +0200 Subject: [PATCH] feat(grpc): governance contract --- app/.dart_tool/extension_discovery/README.md | 31 --- .../extension_discovery/vs_code.json | 1 - app/.dart_tool/package_config.json | 178 -------------- app/.dart_tool/package_graph.json | 230 ------------------ app/.dart_tool/version | 1 - protobufs/operator.proto | 19 +- protobufs/operator/governance.proto | 136 +++++++++++ protobufs/operator/vault/bootstrap.proto | 22 +- protobufs/operator/vault/rekey.proto | 30 +++ protobufs/operator/vault/unseal.proto | 16 +- protobufs/operator/vault/vault.proto | 13 +- protobufs/shared/vault.proto | 7 +- .../gen_erc20_registry.cpython-314.pyc | Bin 8018 -> 0 bytes 13 files changed, 224 insertions(+), 460 deletions(-) delete mode 100644 app/.dart_tool/extension_discovery/README.md delete mode 100644 app/.dart_tool/extension_discovery/vs_code.json delete mode 100644 app/.dart_tool/package_config.json delete mode 100644 app/.dart_tool/package_graph.json delete mode 100644 app/.dart_tool/version create mode 100644 protobufs/operator/governance.proto create mode 100644 protobufs/operator/vault/rekey.proto delete mode 100644 scripts/__pycache__/gen_erc20_registry.cpython-314.pyc diff --git a/app/.dart_tool/extension_discovery/README.md b/app/.dart_tool/extension_discovery/README.md deleted file mode 100644 index 9dc6757..0000000 --- a/app/.dart_tool/extension_discovery/README.md +++ /dev/null @@ -1,31 +0,0 @@ -Extension Discovery Cache -========================= - -This folder is used by `package:extension_discovery` to cache lists of -packages that contains extensions for other packages. - -DO NOT USE THIS FOLDER ----------------------- - - * Do not read (or rely) the contents of this folder. - * Do write to this folder. - -If you're interested in the lists of extensions stored in this folder use the -API offered by package `extension_discovery` to get this information. - -If this package doesn't work for your use-case, then don't try to read the -contents of this folder. It may change, and will not remain stable. - -Use package `extension_discovery` ---------------------------------- - -If you want to access information from this folder. - -Feel free to delete this folder -------------------------------- - -Files in this folder act as a cache, and the cache is discarded if the files -are older than the modification time of `.dart_tool/package_config.json`. - -Hence, it should never be necessary to clear this cache manually, if you find a -need to do please file a bug. diff --git a/app/.dart_tool/extension_discovery/vs_code.json b/app/.dart_tool/extension_discovery/vs_code.json deleted file mode 100644 index b93d172..0000000 --- a/app/.dart_tool/extension_discovery/vs_code.json +++ /dev/null @@ -1 +0,0 @@ -{"version":2,"entries":[{"package":"app","rootUri":"../","packageUri":"lib/"}]} \ No newline at end of file diff --git a/app/.dart_tool/package_config.json b/app/.dart_tool/package_config.json deleted file mode 100644 index 258edaf..0000000 --- a/app/.dart_tool/package_config.json +++ /dev/null @@ -1,178 +0,0 @@ -{ - "configVersion": 2, - "packages": [ - { - "name": "async", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/async-2.13.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "boolean_selector", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "characters", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/characters-1.4.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "clock", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/clock-1.1.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "collection", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/collection-1.19.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "cupertino_icons", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "fake_async", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/fake_async-1.3.3", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/packages/flutter", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "flutter_lints", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_lints-6.0.0", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "flutter_test", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/packages/flutter_test", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "leak_tracker", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "leak_tracker_flutter_testing", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "leak_tracker_testing", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "lints", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/lints-6.1.0", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "matcher", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/matcher-0.12.17", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "material_color_utilities", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1", - "packageUri": "lib/", - "languageVersion": "2.17" - }, - { - "name": "meta", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/meta-1.17.0", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "path", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path-1.9.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "sky_engine", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/bin/cache/pkg/sky_engine", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "source_span", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/source_span-1.10.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "stack_trace", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/stack_trace-1.12.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "stream_channel", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/stream_channel-2.1.4", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "string_scanner", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/string_scanner-1.4.1", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "term_glyph", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/term_glyph-1.2.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "test_api", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/test_api-0.7.7", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "vector_math", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/vector_math-2.2.0", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "vm_service", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/vm_service-15.0.2", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "app", - "rootUri": "../", - "packageUri": "lib/", - "languageVersion": "3.10" - } - ], - "generator": "pub", - "generatorVersion": "3.10.8", - "flutterRoot": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable", - "flutterVersion": "3.38.9", - "pubCache": "file:///Users/kaska/.pub-cache" -} diff --git a/app/.dart_tool/package_graph.json b/app/.dart_tool/package_graph.json deleted file mode 100644 index 2affe54..0000000 --- a/app/.dart_tool/package_graph.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "roots": [ - "app" - ], - "packages": [ - { - "name": "app", - "version": "1.0.0+1", - "dependencies": [ - "cupertino_icons", - "flutter" - ], - "devDependencies": [ - "flutter_lints", - "flutter_test" - ] - }, - { - "name": "flutter_lints", - "version": "6.0.0", - "dependencies": [ - "lints" - ] - }, - { - "name": "flutter_test", - "version": "0.0.0", - "dependencies": [ - "clock", - "collection", - "fake_async", - "flutter", - "leak_tracker_flutter_testing", - "matcher", - "meta", - "path", - "stack_trace", - "stream_channel", - "test_api", - "vector_math" - ] - }, - { - "name": "cupertino_icons", - "version": "1.0.8", - "dependencies": [] - }, - { - "name": "flutter", - "version": "0.0.0", - "dependencies": [ - "characters", - "collection", - "material_color_utilities", - "meta", - "sky_engine", - "vector_math" - ] - }, - { - "name": "lints", - "version": "6.1.0", - "dependencies": [] - }, - { - "name": "stream_channel", - "version": "2.1.4", - "dependencies": [ - "async" - ] - }, - { - "name": "meta", - "version": "1.17.0", - "dependencies": [] - }, - { - "name": "collection", - "version": "1.19.1", - "dependencies": [] - }, - { - "name": "leak_tracker_flutter_testing", - "version": "3.0.10", - "dependencies": [ - "flutter", - "leak_tracker", - "leak_tracker_testing", - "matcher", - "meta" - ] - }, - { - "name": "vector_math", - "version": "2.2.0", - "dependencies": [] - }, - { - "name": "stack_trace", - "version": "1.12.1", - "dependencies": [ - "path" - ] - }, - { - "name": "clock", - "version": "1.1.2", - "dependencies": [] - }, - { - "name": "fake_async", - "version": "1.3.3", - "dependencies": [ - "clock", - "collection" - ] - }, - { - "name": "path", - "version": "1.9.1", - "dependencies": [] - }, - { - "name": "matcher", - "version": "0.12.17", - "dependencies": [ - "async", - "meta", - "stack_trace", - "term_glyph", - "test_api" - ] - }, - { - "name": "test_api", - "version": "0.7.7", - "dependencies": [ - "async", - "boolean_selector", - "collection", - "meta", - "source_span", - "stack_trace", - "stream_channel", - "string_scanner", - "term_glyph" - ] - }, - { - "name": "sky_engine", - "version": "0.0.0", - "dependencies": [] - }, - { - "name": "material_color_utilities", - "version": "0.11.1", - "dependencies": [ - "collection" - ] - }, - { - "name": "characters", - "version": "1.4.0", - "dependencies": [] - }, - { - "name": "async", - "version": "2.13.0", - "dependencies": [ - "collection", - "meta" - ] - }, - { - "name": "leak_tracker_testing", - "version": "3.0.2", - "dependencies": [ - "leak_tracker", - "matcher", - "meta" - ] - }, - { - "name": "leak_tracker", - "version": "11.0.2", - "dependencies": [ - "clock", - "collection", - "meta", - "path", - "vm_service" - ] - }, - { - "name": "term_glyph", - "version": "1.2.2", - "dependencies": [] - }, - { - "name": "string_scanner", - "version": "1.4.1", - "dependencies": [ - "source_span" - ] - }, - { - "name": "source_span", - "version": "1.10.2", - "dependencies": [ - "collection", - "path", - "term_glyph" - ] - }, - { - "name": "boolean_selector", - "version": "2.1.2", - "dependencies": [ - "source_span", - "string_scanner" - ] - }, - { - "name": "vm_service", - "version": "15.0.2", - "dependencies": [] - } - ], - "configVersion": 1 -} \ No newline at end of file diff --git a/app/.dart_tool/version b/app/.dart_tool/version deleted file mode 100644 index 75fffa6..0000000 --- a/app/.dart_tool/version +++ /dev/null @@ -1 +0,0 @@ -3.38.9 \ No newline at end of file diff --git a/protobufs/operator.proto b/protobufs/operator.proto index f780ae3..46509d2 100644 --- a/protobufs/operator.proto +++ b/protobufs/operator.proto @@ -4,25 +4,28 @@ package arbiter.operator; import "operator/auth.proto"; import "operator/evm.proto"; +import "operator/governance.proto"; import "operator/sdk_client.proto"; import "operator/vault/vault.proto"; message OperatorRequest { int32 id = 16; oneof payload { - auth.Request auth = 1; - vault.Request vault = 2; - evm.Request evm = 3; - sdk_client.Request sdk_client = 4; + auth.Request auth = 1; + vault.Request vault = 2; + evm.Request evm = 3; + sdk_client.Request sdk_client = 4; + governance.Request governance = 5; } } message OperatorResponse { optional int32 id = 16; oneof payload { - auth.Response auth = 1; - vault.Response vault = 2; - evm.Response evm = 3; - sdk_client.Response sdk_client = 4; + auth.Response auth = 1; + vault.Response vault = 2; + evm.Response evm = 3; + sdk_client.Response sdk_client = 4; + governance.Response governance = 5; } } diff --git a/protobufs/operator/governance.proto b/protobufs/operator/governance.proto new file mode 100644 index 0000000..132a69f --- /dev/null +++ b/protobufs/operator/governance.proto @@ -0,0 +1,136 @@ +syntax = "proto3"; + +package arbiter.operator.governance; + +message Request { + oneof payload { + CreateProposalRequest create = 1; + CastVoteRequest vote = 2; + QueryPendingRequest query = 3; + } +} + +message CreateProposalRequest { + oneof kind { + ApproveSdkClientPayload approve_sdk_client = 1; + GrantWalletAccessPayload grant_wallet_access = 3; + ApproveServerUpdatePayload approve_server_update = 4; + ReplaceOperatorPayload replace_operator = 5; + UpdateShamirParametersPayload update_shamir_parameters = 6; + ApprovePersistentGrantPayload approve_persistent_grant = 7; + ApproveOneOffTransactionPayload approve_one_off_transaction = 8; + } + optional uint32 ttl_secs = 2; +} + +message ReplaceOperatorPayload { + int32 old_operator_id = 1; + bytes new_pubkey = 2; +} + +message UpdateShamirParametersPayload { + uint32 new_n = 1; +} + +message ApproveServerUpdatePayload {} + +message ApproveSdkClientPayload { + int32 client_id = 1; +} + +message GrantWalletAccessPayload { + int32 wallet_id = 1; + int32 client_id = 2; +} + +message CastVoteRequest { + int32 proposal_id = 1; + bool approve = 2; + bytes signature = 3; +} + +message QueryPendingRequest {} + +message Response { + oneof payload { + CreateProposalResponse created = 1; + VoteResponse voted = 2; + QueryPendingResponse pending = 3; + } +} + +message CreateProposalResponse { + int32 proposal_id = 1; +} + +message VoteResponse { + VoteOutcome outcome = 1; +} + +enum VoteOutcome { + VOTE_OUTCOME_UNSPECIFIED = 0; + VOTE_OUTCOME_PENDING = 1; + VOTE_OUTCOME_APPROVED = 2; + VOTE_OUTCOME_REJECTED = 3; +} + +message ProposalSummary { + int32 id = 1; + string kind = 2; + int32 initiator_id = 3; + int64 expires_at = 4; + int64 approve_count = 5; + int64 reject_count = 6; +} + +message QueryPendingResponse { + repeated ProposalSummary proposals = 1; +} + +message TransactionRateLimitProto { + uint32 count = 1; + int64 window_secs = 2; +} + +message VolumeLimitProto { + bytes max_volume = 1; + int64 window_secs = 2; +} + +message EtherTransferSpecProto { + repeated bytes targets = 1; + VolumeLimitProto limit = 2; +} + +message TokenTransferSpecProto { + bytes token_contract = 1; + optional bytes target = 2; + repeated VolumeLimitProto volume_limits = 3; +} + +message ApproveOneOffTransactionPayload { + int32 client_id = 1; + bytes wallet_address = 2; + uint64 chain_id = 3; + uint64 nonce = 4; + uint64 gas_limit = 5; + bytes max_fee_per_gas = 6; + bytes max_priority_fee_per_gas = 7; + bytes to = 8; + bytes value = 9; + bytes input = 10; +} + +message ApprovePersistentGrantPayload { + int32 wallet_access_id = 1; + uint64 chain_id = 2; + optional int64 valid_from_secs = 3; + optional int64 valid_until_secs = 4; + optional bytes max_gas_fee_per_gas = 5; + optional bytes max_priority_fee_per_gas = 6; + optional TransactionRateLimitProto rate_limit = 7; + oneof specific { + EtherTransferSpecProto ether_transfer = 8; + TokenTransferSpecProto token_transfer = 9; + } +} diff --git a/protobufs/operator/vault/bootstrap.proto b/protobufs/operator/vault/bootstrap.proto index 97e376d..fc0edf8 100644 --- a/protobufs/operator/vault/bootstrap.proto +++ b/protobufs/operator/vault/bootstrap.proto @@ -8,15 +8,35 @@ message BootstrapEncryptedKey { bytes associated_data = 3; } +message DeclareCommittee { + uint32 count = 1; + uint32 recovery_count = 2; +} + +message ContributePassphrase { + bytes passphrase = 1; +} + +message ContributeRecoveryPassphrase { + int32 recovery_operator_id = 1; + bytes passphrase = 2; +} + enum BootstrapResult { BOOTSTRAP_RESULT_UNSPECIFIED = 0; BOOTSTRAP_RESULT_SUCCESS = 1; BOOTSTRAP_RESULT_ALREADY_BOOTSTRAPPED = 2; BOOTSTRAP_RESULT_INVALID_KEY = 3; + BOOTSTRAP_RESULT_AWAITING_CONTRIBUTIONS = 4; } message Request { - BootstrapEncryptedKey encrypted_key = 2; + oneof payload { + BootstrapEncryptedKey encrypted_key = 2; + DeclareCommittee declare_committee = 3; + ContributePassphrase contribute_passphrase = 4; + ContributeRecoveryPassphrase contribute_recovery_passphrase = 5; + } } message Response { diff --git a/protobufs/operator/vault/rekey.proto b/protobufs/operator/vault/rekey.proto new file mode 100644 index 0000000..5a1de2c --- /dev/null +++ b/protobufs/operator/vault/rekey.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package arbiter.operator.vault.rekey; + +message ContributePassphrase { + bytes passphrase = 1; +} + +message ContributeRecoveryPassphrase { + int32 recovery_operator_id = 1; + bytes passphrase = 2; +} + +enum RekeyResult { + REKEY_RESULT_UNSPECIFIED = 0; + REKEY_RESULT_SUCCESS = 1; + REKEY_RESULT_AWAITING_CONTRIBUTIONS = 2; + REKEY_RESULT_NOT_IN_PROGRESS = 3; +} + +message Request { + oneof payload { + ContributePassphrase contribute_passphrase = 1; + ContributeRecoveryPassphrase contribute_recovery_passphrase = 2; + } +} + +message Response { + RekeyResult result = 1; +} diff --git a/protobufs/operator/vault/unseal.proto b/protobufs/operator/vault/unseal.proto index 9378d5d..5e770fd 100644 --- a/protobufs/operator/vault/unseal.proto +++ b/protobufs/operator/vault/unseal.proto @@ -15,17 +15,29 @@ message UnsealEncryptedKey { bytes associated_data = 3; } +message ContributePassphrase { + bytes passphrase = 1; +} + +message ContributeRecoveryPassphrase { + int32 recovery_operator_id = 1; + bytes passphrase = 2; +} + enum UnsealResult { UNSEAL_RESULT_UNSPECIFIED = 0; UNSEAL_RESULT_SUCCESS = 1; UNSEAL_RESULT_INVALID_KEY = 2; UNSEAL_RESULT_UNBOOTSTRAPPED = 3; + UNSEAL_RESULT_AWAITING_CONTRIBUTIONS = 4; } message Request { oneof payload { - UnsealStart start = 1; - UnsealEncryptedKey encrypted_key = 2; + UnsealStart start = 1; + UnsealEncryptedKey encrypted_key = 2; + ContributePassphrase contribute_passphrase = 3; + ContributeRecoveryPassphrase contribute_recovery_passphrase = 4; } } diff --git a/protobufs/operator/vault/vault.proto b/protobufs/operator/vault/vault.proto index 72bd940..6ab1dda 100644 --- a/protobufs/operator/vault/vault.proto +++ b/protobufs/operator/vault/vault.proto @@ -5,20 +5,23 @@ package arbiter.operator.vault; import "google/protobuf/empty.proto"; import "shared/vault.proto"; import "operator/vault/bootstrap.proto"; +import "operator/vault/rekey.proto"; import "operator/vault/unseal.proto"; message Request { oneof payload { google.protobuf.Empty query_state = 1; - unseal.Request unseal = 2; - bootstrap.Request bootstrap = 3; + unseal.Request unseal = 2; + bootstrap.Request bootstrap = 3; + rekey.Request rekey = 4; } } message Response { oneof payload { - arbiter.shared.VaultState state = 1; - unseal.Response unseal = 2; - bootstrap.Response bootstrap = 3; + arbiter.shared.VaultState state = 1; + unseal.Response unseal = 2; + bootstrap.Response bootstrap = 3; + rekey.Response rekey = 4; } } diff --git a/protobufs/shared/vault.proto b/protobufs/shared/vault.proto index 795539f..9e5c2d3 100644 --- a/protobufs/shared/vault.proto +++ b/protobufs/shared/vault.proto @@ -5,7 +5,8 @@ package arbiter.shared; enum VaultState { VAULT_STATE_UNSPECIFIED = 0; VAULT_STATE_UNBOOTSTRAPPED = 1; - VAULT_STATE_SEALED = 2; - VAULT_STATE_UNSEALED = 3; - VAULT_STATE_ERROR = 4; + VAULT_STATE_BOOSTRAPPING = 2; + VAULT_STATE_SEALED = 3; + VAULT_STATE_UNSEALED = 4; + VAULT_STATE_ERROR = 5; } diff --git a/scripts/__pycache__/gen_erc20_registry.cpython-314.pyc b/scripts/__pycache__/gen_erc20_registry.cpython-314.pyc deleted file mode 100644 index 885b7fce51bbc73af4c68193a08d776fcae11319..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8018 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 PrOkgg34*2fU?Tnx7jAM1 -- 2.49.1