feat(common,core,python): support Stellar delegated authentication.
What changed, and why it matters
This commit adds support for a new Stellar blockchain feature called delegated authentication (CAP-71-01 / Protocol 27). It lets an account authorize a transaction through a chain of delegated signers. The device now recognizes and serializes these delegate chains, but when showing the transaction to the user it only displays the top-level authorizing address, not the individual delegates. This is a normal feature addition; there is no direct evidence in the commit of a security vulnerability, though any new signing path deserves careful review.
Treat as a feature commit, not an emergency security patch. Reviewers should verify that recursive delegate parsing has adequate depth limits and memory controls, that the top-level address shown to the user cannot be confused with delegate addresses, and that the signing payload correctly excludes the delegate address field as specified by CAP-71-01.
Security signals we found
New recursive message type (nested_delegates) added to Stellar protocol
UI confirmation intentionally hides delegate signer list from user
Signing payload bound to top-level address per CAP-71-01
No input-length limits visible in generated protobuf code beyond normal vec handling
No explicit security advisory or CVE referenced in commit
Evidence from the diff
The patch extends Trezor’s Stellar message protocol and firmware/core/python/rust client code to handle SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES. It introduces StellarSorobanDelegateSignature (recursive nested delegates) and StellarSorobanAddressCredentialsWithDelegates messages, updates serialization to write the delegate tree, and updates UI confirmation to show only the top-level address_credentials.address. The signing payload remains bound to the top-level address per CAP-71-01. No bug, buffer overflow, or cryptographic flaw is visible in the diff; the change is a feature implementation with test vectors.
Changed components
common/protob/messages-stellar.protocore/src/apps/stellar/operations/layout.pycore/src/apps/stellar/operations/serialize.pycore/src/trezor/messages.pycore/src/trezor/enums/StellarSorobanCredentialsType.pypython/src/trezorlib/stellar.pypython/src/trezorlib/cli/stellar.pypython/src/trezorlib/messages.pyrust/trezor-client/src/protos/generated/messages_stellar.rsInspect captured patch +908 / −60
### common/protob/messages-stellar.proto
@@ -448,20 +448,49 @@ message StellarSorobanAddressCredentials {
required StellarSCVal signature = 4;
}
+/**
+ * A signer that an account delegates its authentication to, as introduced by
+ * CAP-71-01.
+ * Every signature in the delegate tree covers one and the same payload, bound
+ * to the entry's top-level address. The `address` field below is not part of
+ * that payload.
+ * https://github.com/stellar/stellar-protocol/blob/master/core/cap-0071-01.md
+ * https://github.com/stellar/stellar-xdr/blob/v27.0/Stellar-transaction.x#L572
+ * @embed
+ */
+message StellarSorobanDelegateSignature {
+ required string address = 1; // the delegated signer's address
+ required StellarSCVal signature = 2; // signature of the delegated signer, may be SCV_VOID
+ repeated StellarSorobanDelegateSignature nested_delegates = 3; // signers the delegate itself delegates to
+}
+
+/**
+ * Address credentials together with the account's delegated signers (CAP-71-01).
+ * https://github.com/stellar/stellar-protocol/blob/master/core/cap-0071-01.md
+ * https://github.com/stellar/stellar-xdr/blob/v27.0/Stellar-transaction.x#L579
+ * @embed
+ */
+message StellarSorobanAddressCredentialsWithDelegates {
+ required StellarSorobanAddressCredentials address_credentials = 1;
+ repeated StellarSorobanDelegateSignature delegates = 2;
+}
+
/**
* https://github.com/stellar/stellar-xdr/blob/v27.0/Stellar-transaction.x#L593
* @embed
*/
message StellarSorobanCredentials {
required StellarSorobanCredentialsType type = 1;
optional StellarSorobanAddressCredentials address_v2 = 2;
+ optional StellarSorobanAddressCredentialsWithDelegates address_with_delegates = 3;
enum StellarSorobanCredentialsType {
SOROBAN_CREDENTIALS_SOURCE_ACCOUNT = 0;
// 1 is the legacy SOROBAN_CREDENTIALS_ADDRESS, which is due to be
// deprecated in Protocol 28 and is intentionally not supported
reserved 1;
SOROBAN_CREDENTIALS_ADDRESS_V2 = 2;
+ SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES = 3;
};
}
@@ -490,7 +519,8 @@ message StellarInvokeHostFunctionOp {
* The device signs the HashIDPreimage variant selected by envelope_type.
* Currently only ENVELOPE_TYPE_SOROBAN_AUTHORIZATION_WITH_ADDRESS is supported
* (Protocol 27, CAP-71): the payload signed for SOROBAN_CREDENTIALS_ADDRESS_V2
- * credentials, which binds the signature to the authorizing address.
+ * and SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES credentials, which binds the
+ * signature to the authorizing address.
* @start
* @next StellarSorobanAuthorizationSignature
* @next Failure
### common/tests/fixtures/stellar/sign_tx.json
@@ -2710,6 +2710,139 @@
"signature": "k2dCGIudv63WKDpwBA5mzzw5R/93R5glH2ew7mdzryfqtKOkO2JLJweiKDldyc/hXGqAkE33eH1vzXsTQ7ohDw=="
},
"skip_models": ["t1b1"]
+ },
+ {
+ "name": "StellarInvokeHostFunction-auth-delegates",
+ "parameters": {
+ "xdr": "AAAAAgAAAAAvIrnGLwi3dPPr5t1ufbk8PsLL3gJ5Vho9nFIluMMikgAAAMgAAAAAAAAQ4gAAAAEAAAAAAAAAAAAAAABw29iAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABAQQHCg0QExYZHB8iJSgrLjE0Nzo9QENGSUxPUlVYW14AAAAEc3dhcAAAAAEAAAASAAAAASAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/AAAAAQAAAAMAAAABICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8AAAAAOt5osQANu6AAAAABAAAAAwAAAAAAAAAALyK5xi8It3Tz6+bdbn25PD7Cy94CeVYaPZxSJbjDIpIAAAANAAAAQCw8yJ/0CPBfMXjr/JJ12AXgvdL+0nZbhQ6/0rPD/ZosQMJIOqDZs/a5QcdgNfuU6f0lnW4O0sPXDEYK9phI2AkAAAACAAAAAAAAAAAXy3n7K0Eg8rHsZeQZjW4Iso6BP+sB5KQAg5uF4YCAzgAAAA0AAABA7fJMub81b/Mg4frX7TPlpkv4QV4XeWlEPCy0m8qUykkri7T92QPKmgrjvfR+7wsXtA1tsleTgeJkeGTsATb7BAAAAAAAAAAAAAAAAKCapfR6Z1mAL/lV+NwtKhSlyZ0jvpf4ZBJ/+Tg0VaTwAAAADQAAAEAQClS5V3Tpyqug9A4p1eyAzGcKD7lhRYA0GZ7br0N9Tg4Yt40aDsYyS0s3fzmRzZfejVmXL0VgbnEp/Ag3qysLAAAAAAAAAAAAAAAA0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzcAAAANAAAAQNoeRh0UsLyKN20xPfmf/C7uVnJ8xeEjW3qBWatkC5VhjWhz0eYw2TrdD6XjLnI1y8oI/3DRwiSvNC3OePyq2Q8AAAAAAAAAAf/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHgAAAAAQAAAAEAAAAAAAAAANdZeTu8E6KBmoJ8dq22+6ikmu4Af0ny0JktmbglrSxIAAAADQAAAECJX8+25DXrjm2d5jtkkzGzJ6DsZkDyRpiWjkYF71GhPZxsxK1m15JMNl9ZY6nUBEKGC5/0fOpdM0oEJv5qjO4DAAAAAAAAAAAAAAABAgcMERYbICUqLzQ5PkNITVJXXGFma3B1en+EiY6TmJ0AAAAIdHJhbnNmZXIAAAADAAAAEgAAAAEgISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+PwAAABIAAAAAAAAAAC8iucYvCLd08+vm3W59uTw+wsveAnlWGj2cUiW4wyKSAAAACgAAAAAAAAAAAAAAAA7msoAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+ "address_n": "m/44'/148'/0'",
+ "network_passphrase": "Test SDF Network ; September 2015",
+ "tx": {
+ "source_account": "GAXSFOOGF4ELO5HT5PTN23T5XE6D5QWL3YBHSVQ2HWOFEJNYYMRJENBV",
+ "fee": 200,
+ "sequence_number": 4322,
+ "timebounds_start": 0,
+ "timebounds_end": 1893456000,
+ "memo_type": "NONE"
+ },
+ "operations": [
+ {
+ "_message_type": "StellarInvokeHostFunctionOp",
+ "function": {
+ "type": "HOST_FUNCTION_TYPE_INVOKE_CONTRACT",
+ "invoke_contract": {
+ "contract_address": "CAAQIBYKBUIBGFQZDQPSEJJIFMXDCNBXHI6UAQ2GJFGE6USVLBNV5D4J",
+ "function_name": "swap",
+ "args": [
+ {
+ "type": "SCV_ADDRESS",
+ "address": "CAQCCIRDEQSSMJZIFEVCWLBNFYXTAMJSGM2DKNRXHA4TUOZ4HU7D7V6Z"
+ }
+ ]
+ }
+ },
+ "auth": [
+ {
+ "credentials": {
+ "type": "SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES",
+ "address_with_delegates": {
+ "address_credentials": {
+ "address": "CAQCCIRDEQSSMJZIFEVCWLBNFYXTAMJSGM2DKNRXHA4TUOZ4HU7D7V6Z",
+ "nonce": 987654321,
+ "signature_expiration_ledger": 900000,
+ "signature": {
+ "type": "SCV_VOID"
+ }
+ },
+ "delegates": [
+ {
+ "address": "GAXSFOOGF4ELO5HT5PTN23T5XE6D5QWL3YBHSVQ2HWOFEJNYYMRJENBV",
+ "signature": {
+ "type": "SCV_BYTES",
+ "bytes": "2c3cc89ff408f05f3178ebfc9275d805e0bdd2fed2765b850ebfd2b3c3fd9a2c40c2483aa0d9b3f6b941c76035fb94e9fd259d6e0ed2c3d70c460af69848d809"
+ },
+ "nested_delegates": [
+ {
+ "address": "GAL4W6P3FNASB4VR5RS6IGMNNYELFDUBH7VQDZFEACBZXBPBQCAM5QIF",
+ "signature": {
+ "type": "SCV_BYTES",
+ "bytes": "edf24cb9bf356ff320e1fad7ed33e5a64bf8415e177969443c2cb49bca94ca492b8bb4fdd903ca9a0ae3bdf47eef0b17b40d6db2579381e2647864ec0136fb04"
+ }
+ },
+ {
+ "address": "GCQJVJPUPJTVTABP7FK7RXBNFIKKLSM5EO7JP6DECJ77SOBUKWSPB64N",
+ "signature": {
+ "type": "SCV_BYTES",
+ "bytes": "100a54b95774e9caaba0f40e29d5ec80cc670a0fb961458034199edbaf437d4e0e18b78d1a0ec6324b4b377f3991cd97de8d59972f45606e7129fc0837ab2b0b"
+ }
+ }
+ ]
+ },
+ {
+ "address": "GDIEVMRSOQV3JKZ2CNUL2RQV4TTNAISKW4NAC25PQUQKGMWJO6DTOAE7",
+ "signature": {
+ "type": "SCV_BYTES",
+ "bytes": "da1e461d14b0bc8a376d313df99ffc2eee56727cc5e1235b7a8159ab640b95618d6873d1e630d93add0fa5e32e7235cbca08ff70d1c224af342dce78fcaad90f"
+ }
+ },
+ {
+ "address": "CD7757P47P5PT6HX6327J47S6HYO73XN5TV6V2PI47TOLZHD4LQ6BAYK",
+ "signature": {
+ "type": "SCV_VOID"
+ },
+ "nested_delegates": [
+ {
+ "address": "GDLVS6J3XQJ2FAM2QJ6HNLNW7OUKJGXOAB7UT4WQTEWZTOBFVUWERBG7",
+ "signature": {
+ "type": "SCV_BYTES",
+ "bytes": "895fcfb6e435eb8e6d9de63b649331b327a0ec6640f24698968e4605ef51a13d9c6cc4ad66d7924c365f5963a9d40442860b9ff47cea5d334a0426fe6a8cee03"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "root_invocation": {
+ "function": {
+ "type": "SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN",
+ "contract_fn": {
+ "contract_address": "CABAODARCYNSAJJKF42DSPSDJBGVEV24MFTGW4DVPJ7YJCMOSOMJ3SWG",
+ "function_name": "transfer",
+ "args": [
+ {
+ "type": "SCV_ADDRESS",
+ "address": "CAQCCIRDEQSSMJZIFEVCWLBNFYXTAMJSGM2DKNRXHA4TUOZ4HU7D7V6Z"
+ },
+ {
+ "type": "SCV_ADDRESS",
+ "address": "GAXSFOOGF4ELO5HT5PTN23T5XE6D5QWL3YBHSVQ2HWOFEJNYYMRJENBV"
+ },
+ {
+ "type": "SCV_I128",
+ "i128": {
+ "hi": 0,
+ "lo": 250000000
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "ext": {
+ "v": 1,
+ "soroban_data": "0000000000000000000000000000000000000000000000000000000000000000"
+ }
+ },
+ "result": {
+ "public_key": "2f22b9c62f08b774f3ebe6dd6e7db93c3ec2cbde0279561a3d9c5225b8c32292",
+ "signature": "NwACNJ1pg0BEV6LxOq1IgpN0r1Z05pYwlogNFXIclwWt3wF1ekt7UhXdFVBphNTZU2ZzTystrGQZ+xChuMzmBw=="
+ },
+ "skip_models": ["t1b1"]
}
]
}
### core/.changelog.d/7311.added
@@ -0,0 +1 @@
+Stellar: Support Protocol 27 delegated authentication.
### core/src/apps/stellar/operations/layout.py
@@ -547,13 +547,22 @@ async def _confirm_auth_entry(
elif creds.type == StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2:
if creds.address_v2 is None:
raise DataError("Stellar: missing address_v2 credentials")
-
authorizing_address = creds.address_v2.address
- await confirm_address(
- f"{TR.words__authorization} #{position}",
- authorizing_address,
- description=TR.words__address,
- br_name="op_auth_entry_address",
+ await _confirm_authorizing_address(
+ f"{TR.words__authorization} #{position}", authorizing_address
+ )
+ elif (
+ creds.type
+ == StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES
+ ):
+ if creds.address_with_delegates is None:
+ raise DataError("Stellar: missing address_with_delegates credentials")
+ # The delegated signers themselves are not shown: like the nonce and the
+ # signature, they are how this address established its authorization,
+ # not what it authorizes.
+ authorizing_address = creds.address_with_delegates.address_credentials.address
+ await _confirm_authorizing_address(
+ f"{TR.words__authorization} #{position}", authorizing_address
)
else:
raise ProcessError("Stellar: unsupported credentials type")
@@ -567,3 +576,12 @@ async def _confirm_auth_entry(
authorizing_address,
is_root=is_root,
)
+
+
+async def _confirm_authorizing_address(title: str, address: str) -> None:
+ await confirm_address(
+ title,
+ address,
+ description=TR.words__address,
+ br_name="op_auth_entry_address",
+ )
### core/src/apps/stellar/operations/serialize.py
@@ -40,8 +40,10 @@
StellarPaymentOp,
StellarSetOptionsOp,
StellarSorobanAddressCredentials,
+ StellarSorobanAddressCredentialsWithDelegates,
StellarSorobanAuthorizationEntry,
StellarSorobanCredentials,
+ StellarSorobanDelegateSignature,
)
from trezor.utils import Writer
@@ -246,6 +248,13 @@ def _write_soroban_credentials(w: Writer, msg: StellarSorobanCredentials) -> Non
if msg.address_v2 is None:
raise DataError("Stellar: missing address credentials")
_write_soroban_address_credentials(w, msg.address_v2)
+ elif (
+ msg.type
+ == StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES
+ ):
+ if msg.address_with_delegates is None:
+ raise DataError("Stellar: missing address credentials with delegates")
+ _write_soroban_address_credentials_with_delegates(w, msg.address_with_delegates)
else:
raise ProcessError("Stellar: unsupported credentials type")
@@ -257,3 +266,18 @@ def _write_soroban_address_credentials(
write_int64(w, msg.nonce)
write_uint32(w, msg.signature_expiration_ledger)
write_sc_val(w, msg.signature)
+
+
+def _write_soroban_address_credentials_with_delegates(
+ w: Writer, msg: StellarSorobanAddressCredentialsWithDelegates
+) -> None:
+ _write_soroban_address_credentials(w, msg.address_credentials)
+ write_vec(w, msg.delegates, _write_soroban_delegate_signature)
+
+
+def _write_soroban_delegate_signature(
+ w: Writer, msg: StellarSorobanDelegateSignature
+) -> None:
+ write_sc_address(w, msg.address)
+ write_sc_val(w, msg.signature)
+ write_vec(w, msg.nested_delegates, _write_soroban_delegate_signature)
### core/src/trezor/enums/StellarSorobanCredentialsType.py
@@ -4,3 +4,4 @@
SOROBAN_CREDENTIALS_SOURCE_ACCOUNT = 0
SOROBAN_CREDENTIALS_ADDRESS_V2 = 2
+SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES = 3
### core/src/trezor/enums/__init__.py
@@ -418,6 +418,7 @@ class StellarHostFunctionType(IntEnum):
class StellarSorobanCredentialsType(IntEnum):
SOROBAN_CREDENTIALS_SOURCE_ACCOUNT = 0
SOROBAN_CREDENTIALS_ADDRESS_V2 = 2
+ SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES = 3
class StellarSorobanAuthorizationEnvelopeType(IntEnum):
ENVELOPE_TYPE_SOROBAN_AUTHORIZATION_WITH_ADDRESS = 10
### core/src/trezor/messages.py
@@ -6755,15 +6755,51 @@ def __init__(
def is_type_of(cls, msg: Any) -> TypeGuard["StellarSorobanAddressCredentials"]:
return isinstance(msg, cls)
+ class StellarSorobanDelegateSignature(protobuf.MessageType):
+ address: "str"
+ signature: "StellarSCVal"
+ nested_delegates: "list[StellarSorobanDelegateSignature]"
+
+ def __init__(
+ self,
+ *,
+ address: "str",
+ signature: "StellarSCVal",
+ nested_delegates: "list[StellarSorobanDelegateSignature] | None" = None,
+ ) -> None:
+ pass
+
+ @classmethod
+ def is_type_of(cls, msg: Any) -> TypeGuard["StellarSorobanDelegateSignature"]:
+ return isinstance(msg, cls)
+
+ class StellarSorobanAddressCredentialsWithDelegates(protobuf.MessageType):
+ address_credentials: "StellarSorobanAddressCredentials"
+ delegates: "list[StellarSorobanDelegateSignature]"
+
+ def __init__(
+ self,
+ *,
+ address_credentials: "StellarSorobanAddressCredentials",
+ delegates: "list[StellarSorobanDelegateSignature] | None" = None,
+ ) -> None:
+ pass
+
+ @classmethod
+ def is_type_of(cls, msg: Any) -> TypeGuard["StellarSorobanAddressCredentialsWithDelegates"]:
+ return isinstance(msg, cls)
+
class StellarSorobanCredentials(protobuf.MessageType):
type: "StellarSorobanCredentialsType"
address_v2: "StellarSorobanAddressCredentials | None"
+ address_with_delegates: "StellarSorobanAddressCredentialsWithDelegates | None"
def __init__(
self,
*,
type: "StellarSorobanCredentialsType",
address_v2: "StellarSorobanAddressCredentials | None" = None,
+ address_with_delegates: "StellarSorobanAddressCredentialsWithDelegates | None" = None,
) -> None:
pass
### python/.changelog.d/7311.added
@@ -0,0 +1 @@
+Stellar: Support Protocol 27 delegated authentication.
### python/src/trezorlib/cli/stellar.py
@@ -181,10 +181,16 @@ def sign_soroban_authorization(
"""Sign a base64-encoded Soroban authorization entry.
Takes an unsigned SorobanAuthorizationEntry XDR with
- SOROBAN_CREDENTIALS_ADDRESS_V2 credentials (Protocol 27) and returns the
- base64-encoded signature of its authorization payload. The signed payload
- commits to the entry's signature_expiration_ledger; it must already be
- set to the intended value, or overridden with --valid-until-ledger.
+ SOROBAN_CREDENTIALS_ADDRESS_V2 or SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES
+ credentials (Protocol 27) and returns the base64-encoded signature of its
+ authorization payload. The signed payload commits to the entry's
+ signature_expiration_ledger; it must already be set to the intended value,
+ or overridden with --valid-until-ledger.
+
+ For a given entry both credential types produce the same payload, bound to
+ its top-level address, so an ADDRESS_WITH_DELEGATES entry is signed the same
+ way whether the signature is to go into the top-level credentials or into
+ one of the delegate slots -- -n/--address only picks the signing key.
"""
if not stellar.HAVE_STELLAR_SDK:
click.echo("Stellar requirements not installed.")
@@ -207,14 +213,17 @@ def sign_soroban_authorization(
)
sys.exit(1)
- if (
- entry_xdr.credentials.type
- != stellar_xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2
+ if entry_xdr.credentials.type not in (
+ stellar_xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2,
+ stellar_xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES,
):
click.echo(
f"Unsupported SorobanCredentials type: {entry_xdr.credentials.type}."
)
- click.echo("Only SOROBAN_CREDENTIALS_ADDRESS_V2 entries can be signed.")
+ click.echo(
+ "Only SOROBAN_CREDENTIALS_ADDRESS_V2 and "
+ "SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES entries can be signed."
+ )
sys.exit(1)
address_n = tools.parse_path(address)
### python/src/trezorlib/messages.py
@@ -476,6 +476,7 @@ class StellarHostFunctionType(IntEnum):
class StellarSorobanCredentialsType(IntEnum):
SOROBAN_CREDENTIALS_SOURCE_ACCOUNT = 0
SOROBAN_CREDENTIALS_ADDRESS_V2 = 2
+ SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES = 3
class StellarSorobanAuthorizationEnvelopeType(IntEnum):
@@ -8677,21 +8678,61 @@ def __init__(
self.signature = signature
+class StellarSorobanDelegateSignature(protobuf.MessageType):
+ MESSAGE_WIRE_TYPE = None
+ FIELDS = {
+ 1: protobuf.Field("address", "string", repeated=False, required=True),
+ 2: protobuf.Field("signature", "StellarSCVal", repeated=False, required=True),
+ 3: protobuf.Field("nested_delegates", "StellarSorobanDelegateSignature", repeated=True, required=False, default=None),
+ }
+
+ def __init__(
+ self,
+ *,
+ address: "str",
+ signature: "StellarSCVal",
+ nested_delegates: Optional[Sequence["StellarSorobanDelegateSignature"]] = None,
+ ) -> None:
+ self.nested_delegates: Sequence["StellarSorobanDelegateSignature"] = nested_delegates if nested_delegates is not None else []
+ self.address = address
+ self.signature = signature
+
+
+class StellarSorobanAddressCredentialsWithDelegates(protobuf.MessageType):
+ MESSAGE_WIRE_TYPE = None
+ FIELDS = {
+ 1: protobuf.Field("address_credentials", "StellarSorobanAddressCredentials", repeated=False, required=True),
+ 2: protobuf.Field("delegates", "StellarSorobanDelegateSignature", repeated=True, required=False, default=None),
+ }
+
+ def __init__(
+ self,
+ *,
+ address_credentials: "StellarSorobanAddressCredentials",
+ delegates: Optional[Sequence["StellarSorobanDelegateSignature"]] = None,
+ ) -> None:
+ self.delegates: Sequence["StellarSorobanDelegateSignature"] = delegates if delegates is not None else []
+ self.address_credentials = address_credentials
+
+
class StellarSorobanCredentials(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
FIELDS = {
1: protobuf.Field("type", "StellarSorobanCredentialsType", repeated=False, required=True),
2: protobuf.Field("address_v2", "StellarSorobanAddressCredentials", repeated=False, required=False, default=None),
+ 3: protobuf.Field("address_with_delegates", "StellarSorobanAddressCredentialsWithDelegates", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
type: "StellarSorobanCredentialsType",
address_v2: Optional["StellarSorobanAddressCredentials"] = None,
+ address_with_delegates: Optional["StellarSorobanAddressCredentialsWithDelegates"] = None,
) -> None:
self.type = type
self.address_v2 = address_v2
+ self.address_with_delegates = address_with_delegates
class StellarSorobanAuthorizationEntry(protobuf.MessageType):
### python/src/trezorlib/stellar.py
@@ -184,22 +184,38 @@ def from_authorization_entry(
The resulting message carries exactly the fields committed into the
entry's authorization payload (the WITH_ADDRESS preimage of Protocol 27).
- Only SOROBAN_CREDENTIALS_ADDRESS_V2 entries are supported.
+ Only SOROBAN_CREDENTIALS_ADDRESS_V2 and
+ SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES entries are supported.
+
+ For entries with delegates the payload is bound to the entry's top-level
+ address: under CAP-71-01 every delegated signer, however deeply nested,
+ authenticates that same payload and context, so one request serves the
+ top-level account's own signer and any of its delegates -- `address_n`
+ decides which key signs.
See `from_envelope` for `asset_hints`. Matching them needs the network the
entry is signed for, so `network_passphrase` is required alongside them.
"""
if not HAVE_STELLAR_SDK:
raise RuntimeError("Stellar SDK not available")
- if not HAVE_STELLAR_SDK_PROTOCOL_27 or (
- entry.credentials.type
- != xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2
- ):
+ credentials = None
+ if HAVE_STELLAR_SDK_PROTOCOL_27:
+ if (
+ entry.credentials.type
+ == xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2
+ ):
+ assert entry.credentials.address_v2 is not None
+ credentials = entry.credentials.address_v2
+ elif (
+ entry.credentials.type
+ == xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES
+ ):
+ assert entry.credentials.address_with_delegates is not None
+ credentials = entry.credentials.address_with_delegates.address_credentials
+ if credentials is None:
raise ValueError(
f"Unsupported SorobanCredentials type: {entry.credentials.type}"
)
- credentials = entry.credentials.address_v2
- assert credentials is not None
invocation = _read_authorized_invocation(entry.root_invocation)
asset_hints = list(asset_hints)
@@ -671,6 +687,31 @@ def _read_address_credentials(
)
+def _read_delegate_signature(
+ delegate: xdr.SorobanDelegateSignature,
+) -> messages.StellarSorobanDelegateSignature:
+ """Read SorobanDelegateSignature from XDR."""
+ return messages.StellarSorobanDelegateSignature(
+ address=_read_sc_address(delegate.address),
+ signature=_read_sc_val(delegate.signature),
+ nested_delegates=[
+ _read_delegate_signature(nested) for nested in delegate.nested_delegates
+ ],
+ )
+
+
+def _read_address_credentials_with_delegates(
+ credentials: xdr.SorobanAddressCredentialsWithDelegates,
+) -> messages.StellarSorobanAddressCredentialsWithDelegates:
+ """Read SorobanAddressCredentialsWithDelegates from XDR."""
+ return messages.StellarSorobanAddressCredentialsWithDelegates(
+ address_credentials=_read_address_credentials(credentials.address_credentials),
+ delegates=[
+ _read_delegate_signature(delegate) for delegate in credentials.delegates
+ ],
+ )
+
+
def _read_credentials(
credentials: xdr.SorobanCredentials,
) -> messages.StellarSorobanCredentials:
@@ -691,6 +732,18 @@ def _read_credentials(
type=messages.StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2,
address_v2=_read_address_credentials(credentials.address_v2),
)
+ elif (
+ HAVE_STELLAR_SDK_PROTOCOL_27
+ and credentials.type
+ == xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES
+ ):
+ assert credentials.address_with_delegates is not None
+ return messages.StellarSorobanCredentials(
+ type=messages.StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES,
+ address_with_delegates=_read_address_credentials_with_delegates(
+ credentials.address_with_delegates
+ ),
+ )
else:
# The legacy, to-be-deprecated SOROBAN_CREDENTIALS_ADDRESS is
# intentionally not supported.
### python/tests/test_stellar.py
@@ -979,6 +979,7 @@ def test_claim_claimable_balance():
SOROBAN_SOURCE = "GAXSFOOGF4ELO5HT5PTN23T5XE6D5QWL3YBHSVQ2HWOFEJNYYMRJENBV"
SOROBAN_CONTRACT = "CABQUEIYD4TC2NB3IJEVAV26MVWHG6UBRCHZNHNEVOZLTQGHZ3K5ZIRI"
SOROBAN_DESTINATION = "GBOVKZBEM2YYLOCDCUXJ4IMRKHN4LCJAE7WEAEA2KF562XFAGDBOB64V"
+SOROBAN_DELEGATE = "GCRW4NZ45MPVTYRD6MV4EOT2WB4BIWLENHREU2BQLFF3DL4IPH36NBDL"
# A real asset, so the address of its Stellar Asset Contract can be derived
# (CAP-46-2) and asset hints matched against invocations of that contract.
@@ -1136,6 +1137,65 @@ def test_from_authorization_entry_ignores_signature():
)
+def make_delegates_authorization_entry(
+ address, nonce, signature_expiration_ledger, delegates=()
+):
+ """A CAP-71-01 entry whose account delegates authentication to other addresses."""
+ return stellar_xdr.SorobanAuthorizationEntry(
+ credentials=stellar_xdr.SorobanCredentials(
+ type=stellar_xdr.SorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES,
+ address_with_delegates=stellar_xdr.SorobanAddressCredentialsWithDelegates(
+ address_credentials=stellar_xdr.SorobanAddressCredentials(
+ address=Address(address).to_xdr_sc_address(),
+ nonce=stellar_xdr.Int64(nonce),
+ signature_expiration_ledger=stellar_xdr.Uint32(
+ signature_expiration_ledger
+ ),
+ signature=scval.to_void(),
+ ),
+ delegates=list(delegates),
+ ),
+ ),
+ root_invocation=make_soroban_invocation(),
+ )
+
+
+def make_delegate(address, signature=None, nested_delegates=()):
+ return stellar_xdr.SorobanDelegateSignature(
+ address=Address(address).to_xdr_sc_address(),
+ signature=signature if signature is not None else scval.to_void(),
+ nested_delegates=list(nested_delegates),
+ )
+
+
+@skip_if_no_protocol_27
+def test_from_authorization_entry_with_delegates():
+ # Under CAP-71-01 every delegated signer authenticates the same payload,
+ # bound to the entry's top-level address, so that is what the request
+ # carries.
+ entry = make_delegates_authorization_entry(
+ SOROBAN_CONTRACT,
+ 123456789,
+ 600000,
+ delegates=[
+ make_delegate(SOROBAN_SOURCE, scval.to_bytes(b"already signed")),
+ make_delegate(
+ SOROBAN_CONTRACT,
+ nested_delegates=[make_delegate(SOROBAN_DELEGATE)],
+ ),
+ ],
+ )
+
+ authorization = stellar.from_authorization_entry(entry)
+
+ assert authorization == messages.StellarSorobanAuthorizationWithAddress(
+ nonce=123456789,
+ signature_expiration_ledger=600000,
+ address=SOROBAN_CONTRACT,
+ invocation=expected_invocation("transfer", 500_111_000),
+ )
+
+
@skip_if_no_protocol_27
def test_from_authorization_entry_unsupported_credentials():
entry = stellar_xdr.SorobanAuthorizationEntry(
@@ -1190,6 +1250,35 @@ def make_sac_transfer_tx(auth=()):
return make_default_tx().append_operation(op).build()
+@skip_if_no_protocol_27
+def test_from_envelope_delegates():
+ # The whole delegate tree reaches the device: it is part of the transaction
+ # the device signs.
+ entry = make_delegates_authorization_entry(
+ SOROBAN_CONTRACT,
+ 123456789,
+ 600000,
+ delegates=[
+ make_delegate(SOROBAN_SOURCE),
+ make_delegate(
+ SOROBAN_CONTRACT,
+ nested_delegates=[make_delegate(SOROBAN_DELEGATE)],
+ ),
+ ],
+ )
+
+ _, operations, _ = stellar.from_envelope(make_sac_transfer_tx(auth=[entry]))
+
+ credentials = operations[0].auth[0].credentials
+ assert (
+ credentials.type
+ == messages.StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES
+ )
+ delegates = credentials.address_with_delegates.delegates
+ assert [d.address for d in delegates] == [SOROBAN_SOURCE, SOROBAN_CONTRACT]
+ assert [d.address for d in delegates[1].nested_delegates] == [SOROBAN_DELEGATE]
+
+
def test_from_envelope_asset_hints():
# the entry authorizes a non-SAC root with a SAC sub-invocation
entry = stellar_xdr.SorobanAuthorizationEntry(
### rust/trezor-client/src/protos/generated/messages_stellar.rs
@@ -9402,6 +9402,373 @@ impl ::protobuf::reflect::ProtobufValue for StellarSorobanAddressCredentials {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+// @@protoc_insertion_point(message:hw.trezor.messages.stellar.StellarSorobanDelegateSignature)
+#[derive(PartialEq,Clone,Default,Debug)]
+pub struct StellarSorobanDelegateSignature {
+ // message fields
+ // @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanDelegateSignature.address)
+ pub address: ::std::option::Option<::std::string::String>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanDelegateSignature.signature)
+ pub signature: ::protobuf::MessageField<StellarSCVal>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanDelegateSignature.nested_delegates)
+ pub nested_delegates: ::std::vec::Vec<StellarSorobanDelegateSignature>,
+ // special fields
+ // @@protoc_insertion_point(special_field:hw.trezor.messages.stellar.StellarSorobanDelegateSignature.special_fields)
+ pub special_fields: ::protobuf::SpecialFields,
+}
+
+impl<'a> ::std::default::Default for &'a StellarSorobanDelegateSignature {
+ fn default() -> &'a StellarSorobanDelegateSignature {
+ <StellarSorobanDelegateSignature as ::protobuf::Message>::default_instance()
+ }
+}
+
+impl StellarSorobanDelegateSignature {
+ pub fn new() -> StellarSorobanDelegateSignature {
+ ::std::default::Default::default()
+ }
+
+ // required string address = 1;
+
+ pub fn address(&self) -> &str {
+ match self.address.as_ref() {
+ Some(v) => v,
+ None => "",
+ }
+ }
+
+ pub fn clear_address(&mut self) {
+ self.address = ::std::option::Option::None;
+ }
+
+ pub fn has_address(&self) -> bool {
+ self.address.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_address(&mut self, v: ::std::string::String) {
+ self.address = ::std::option::Option::Some(v);
+ }
+
+ // Mutable pointer to the field.
+ // If field is not initialized, it is initialized with default value first.
+ pub fn mut_address(&mut self) -> &mut ::std::string::String {
+ if self.address.is_none() {
+ self.address = ::std::option::Option::Some(::std::string::String::new());
+ }
+ self.address.as_mut().unwrap()
+ }
+
+ // Take field
+ pub fn take_address(&mut self) -> ::std::string::String {
+ self.address.take().unwrap_or_else(|| ::std::string::String::new())
+ }
+
+ fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
+ let mut fields = ::std::vec::Vec::with_capacity(3);
+ let mut oneofs = ::std::vec::Vec::with_capacity(0);
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "address",
+ |m: &StellarSorobanDelegateSignature| { &m.address },
+ |m: &mut StellarSorobanDelegateSignature| { &mut m.address },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, StellarSCVal>(
+ "signature",
+ |m: &StellarSorobanDelegateSignature| { &m.signature },
+ |m: &mut StellarSorobanDelegateSignature| { &mut m.signature },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
+ "nested_delegates",
+ |m: &StellarSorobanDelegateSignature| { &m.nested_delegates },
+ |m: &mut StellarSorobanDelegateSignature| { &mut m.nested_delegates },
+ ));
+ ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<StellarSorobanDelegateSignature>(
+ "StellarSorobanDelegateSignature",
+ fields,
+ oneofs,
+ )
+ }
+}
+
+impl ::protobuf::Message for StellarSorobanDelegateSignature {
+ const NAME: &'static str = "StellarSorobanDelegateSignature";
+
+ fn is_initialized(&self) -> bool {
+ if self.address.is_none() {
+ return false;
+ }
+ if self.signature.is_none() {
+ return false;
+ }
+ for v in &self.signature {
+ if !v.is_initialized() {
+ return false;
+ }
+ };
+ for v in &self.nested_delegates {
+ if !v.is_initialized() {
+ return false;
+ }
+ };
+ true
+ }
+
+ fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+ while let Some(tag) = is.read_raw_tag_or_eof()? {
+ match tag {
+ 10 => {
+ self.address = ::std::option::Option::Some(is.read_string()?);
+ },
+ 18 => {
+ ::protobuf::rt::read_singular_message_into_field(is, &mut self.signature)?;
+ },
+ 26 => {
+ self.nested_delegates.push(is.read_message()?);
+ },
+ tag => {
+ ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
+ },
+ };
+ }
+ ::std::result::Result::Ok(())
+ }
+
+ // Compute sizes of nested messages
+ #[allow(unused_variables)]
+ fn compute_size(&self) -> u64 {
+ let mut my_size = 0;
+ if let Some(v) = self.address.as_ref() {
+ my_size += ::protobuf::rt::string_size(1, &v);
+ }
+ if let Some(v) = self.signature.as_ref() {
+ let len = v.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ }
+ for value in &self.nested_delegates {
+ let len = value.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ };
+ my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+ self.special_fields.cached_size().set(my_size as u32);
+ my_size
+ }
+
+ fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+ if let Some(v) = self.address.as_ref() {
+ os.write_string(1, v)?;
+ }
+ if let Some(v) = self.signature.as_ref() {
+ ::protobuf::rt::write_message_field_with_cached_size(2, v, os)?;
+ }
+ for v in &self.nested_delegates {
+ ::protobuf::rt::write_message_field_with_cached_size(3, v, os)?;
+ };
+ os.write_unknown_fields(self.special_fields.unknown_fields())?;
+ ::std::result::Result::Ok(())
+ }
+
+ fn special_fields(&self) -> &::protobuf::SpecialFields {
+ &self.special_fields
+ }
+
+ fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+ &mut self.special_fields
+ }
+
+ fn new() -> StellarSorobanDelegateSignature {
+ StellarSorobanDelegateSignature::new()
+ }
+
+ fn clear(&mut self) {
+ self.address = ::std::option::Option::None;
+ self.signature.clear();
+ self.nested_delegates.clear();
+ self.special_fields.clear();
+ }
+
+ fn default_instance() -> &'static StellarSorobanDelegateSignature {
+ static instance: StellarSorobanDelegateSignature = StellarSorobanDelegateSignature {
+ address: ::std::option::Option::None,
+ signature: ::protobuf::MessageField::none(),
+ nested_delegates: ::std::vec::Vec::new(),
+ special_fields: ::protobuf::SpecialFields::new(),
+ };
+ &instance
+ }
+}
+
+impl ::protobuf::MessageFull for StellarSorobanDelegateSignature {
+ fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
+ static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
+ descriptor.get(|| file_descriptor().message_by_package_relative_name("StellarSorobanDelegateSignature").unwrap()).clone()
+ }
+}
+
+impl ::std::fmt::Display for StellarSorobanDelegateSignature {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ ::protobuf::text_format::fmt(self, f)
+ }
+}
+
+impl ::protobuf::reflect::ProtobufValue for StellarSorobanDelegateSignature {
+ type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
+}
+
+// @@protoc_insertion_point(message:hw.trezor.messages.stellar.StellarSorobanAddressCredentialsWithDelegates)
+#[derive(PartialEq,Clone,Default,Debug)]
+pub struct StellarSorobanAddressCredentialsWithDelegates {
+ // message fields
+ // @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanAddressCredentialsWithDelegates.address_credentials)
+ pub address_credentials: ::protobuf::MessageField<StellarSorobanAddressCredentials>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanAddressCredentialsWithDelegates.delegates)
+ pub delegates: ::std::vec::Vec<StellarSorobanDelegateSignature>,
+ // special fields
+ // @@protoc_insertion_point(special_field:hw.trezor.messages.stellar.StellarSorobanAddressCredentialsWithDelegates.special_fields)
+ pub special_fields: ::protobuf::SpecialFields,
+}
+
+impl<'a> ::std::default::Default for &'a StellarSorobanAddressCredentialsWithDelegates {
+ fn default() -> &'a StellarSorobanAddressCredentialsWithDelegates {
+ <StellarSorobanAddressCredentialsWithDelegates as ::protobuf::Message>::default_instance()
+ }
+}
+
+impl StellarSorobanAddressCredentialsWithDelegates {
+ pub fn new() -> StellarSorobanAddressCredentialsWithDelegates {
+ ::std::default::Default::default()
+ }
+
+ fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
+ let mut fields = ::std::vec::Vec::with_capacity(2);
+ let mut oneofs = ::std::vec::Vec::with_capacity(0);
+ fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, StellarSorobanAddressCredentials>(
+ "address_credentials",
+ |m: &StellarSorobanAddressCredentialsWithDelegates| { &m.address_credentials },
+ |m: &mut StellarSorobanAddressCredentialsWithDelegates| { &mut m.address_credentials },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
+ "delegates",
+ |m: &StellarSorobanAddressCredentialsWithDelegates| { &m.delegates },
+ |m: &mut StellarSorobanAddressCredentialsWithDelegates| { &mut m.delegates },
+ ));
+ ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<StellarSorobanAddressCredentialsWithDelegates>(
+ "StellarSorobanAddressCredentialsWithDelegates",
+ fields,
+ oneofs,
+ )
+ }
+}
+
+impl ::protobuf::Message for StellarSorobanAddressCredentialsWithDelegates {
+ const NAME: &'static str = "StellarSorobanAddressCredentialsWithDelegates";
+
+ fn is_initialized(&self) -> bool {
+ if self.address_credentials.is_none() {
+ return false;
+ }
+ for v in &self.address_credentials {
+ if !v.is_initialized() {
+ return false;
+ }
+ };
+ for v in &self.delegates {
+ if !v.is_initialized() {
+ return false;
+ }
+ };
+ true
+ }
+
+ fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+ while let Some(tag) = is.read_raw_tag_or_eof()? {
+ match tag {
+ 10 => {
+ ::protobuf::rt::read_singular_message_into_field(is, &mut self.address_credentials)?;
+ },
+ 18 => {
+ self.delegates.push(is.read_message()?);
+ },
+ tag => {
+ ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
+ },
+ };
+ }
+ ::std::result::Result::Ok(())
+ }
+
+ // Compute sizes of nested messages
+ #[allow(unused_variables)]
+ fn compute_size(&self) -> u64 {
+ let mut my_size = 0;
+ if let Some(v) = self.address_credentials.as_ref() {
+ let len = v.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ }
+ for value in &self.delegates {
+ let len = value.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ };
+ my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+ self.special_fields.cached_size().set(my_size as u32);
+ my_size
+ }
+
+ fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+ if let Some(v) = self.address_credentials.as_ref() {
+ ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?;
+ }
+ for v in &self.delegates {
+ ::protobuf::rt::write_message_field_with_cached_size(2, v, os)?;
+ };
+ os.write_unknown_fields(self.special_fields.unknown_fields())?;
+ ::std::result::Result::Ok(())
+ }
+
+ fn special_fields(&self) -> &::protobuf::SpecialFields {
+ &self.special_fields
+ }
+
+ fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+ &mut self.special_fields
+ }
+
+ fn new() -> StellarSorobanAddressCredentialsWithDelegates {
+ StellarSorobanAddressCredentialsWithDelegates::new()
+ }
+
+ fn clear(&mut self) {
+ self.address_credentials.clear();
+ self.delegates.clear();
+ self.special_fields.clear();
+ }
+
+ fn default_instance() -> &'static StellarSorobanAddressCredentialsWithDelegates {
+ static instance: StellarSorobanAddressCredentialsWithDelegates = StellarSorobanAddressCredentialsWithDelegates {
+ address_credentials: ::protobuf::MessageField::none(),
+ delegates: ::std::vec::Vec::new(),
+ special_fields: ::protobuf::SpecialFields::new(),
+ };
+ &instance
+ }
+}
+
+impl ::protobuf::MessageFull for StellarSorobanAddressCredentialsWithDelegates {
+ fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
+ static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
+ descriptor.get(|| file_descriptor().message_by_package_relative_name("StellarSorobanAddressCredentialsWithDelegates").unwrap()).clone()
+ }
+}
+
+impl ::std::fmt::Display for StellarSorobanAddressCredentialsWithDelegates {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ ::protobuf::text_format::fmt(self, f)
+ }
+}
+
+impl ::protobuf::reflect::ProtobufValue for StellarSorobanAddressCredentialsWithDelegates {
+ type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
+}
+
// @@protoc_insertion_point(message:hw.trezor.messages.stellar.StellarSorobanCredentials)
#[derive(PartialEq,Clone,Default,Debug)]
pub struct StellarSorobanCredentials {
@@ -9410,6 +9777,8 @@ pub struct StellarSorobanCredentials {
pub type_: ::std::option::Option<::protobuf::EnumOrUnknown<stellar_soroban_credentials::StellarSorobanCredentialsType>>,
// @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanCredentials.address_v2)
pub address_v2: ::protobuf::MessageField<StellarSorobanAddressCredentials>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.stellar.StellarSorobanCredentials.address_with_delegates)
+ pub address_with_delegates: ::protobuf::MessageField<StellarSorobanAddressCredentialsWithDelegates>,
// special fields
// @@protoc_insertion_point(special_field:hw.trezor.messages.stellar.StellarSorobanCredentials.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -9449,7 +9818,7 @@ impl StellarSorobanCredentials {
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(2);
+ let mut fields = ::std::vec::Vec::with_capacity(3);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"type",
@@ -9461,6 +9830,11 @@ impl StellarSorobanCredentials {
|m: &StellarSorobanCredentials| { &m.address_v2 },
|m: &mut StellarSorobanCredentials| { &mut m.address_v2 },
));
+ fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, StellarSorobanAddressCredentialsWithDelegates>(
+ "address_with_delegates",
+ |m: &StellarSorobanCredentials| { &m.address_with_delegates },
+ |m: &mut StellarSorobanCredentials| { &mut m.address_with_delegates },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<StellarSorobanCredentials>(
"StellarSorobanCredentials",
fields,
@@ -9481,6 +9855,11 @@ impl ::protobuf::Message for StellarSorobanCredentials {
return false;
}
};
+ for v in &self.address_with_delegates {
+ if !v.is_initialized() {
+ return false;
+ }
+ };
true
}
@@ -9493,6 +9872,9 @@ impl ::protobuf::Message for StellarSorobanCredentials {
18 => {
::protobuf::rt::read_singular_message_into_field(is, &mut self.address_v2)?;
},
+ 26 => {
+ ::protobuf::rt::read_singular_message_into_field(is, &mut self.address_with_delegates)?;
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -9512,6 +9894,10 @@ impl ::protobuf::Message for StellarSorobanCredentials {
let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
}
+ if let Some(v) = self.address_with_delegates.as_ref() {
+ let len = v.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -9524,6 +9910,9 @@ impl ::protobuf::Message for StellarSorobanCredentials {
if let Some(v) = self.address_v2.as_ref() {
::protobuf::rt::write_message_field_with_cached_size(2, v, os)?;
}
+ if let Some(v) = self.address_with_delegates.as_ref() {
+ ::protobuf::rt::write_message_field_with_cached_size(3, v, os)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -9543,13 +9932,15 @@ impl ::protobuf::Message for StellarSorobanCredentials {
fn clear(&mut self) {
self.type_ = ::std::option::Option::None;
self.address_v2.clear();
+ self.address_with_delegates.clear();
self.special_fields.clear();
}
fn default_instance() -> &'static StellarSorobanCredentials {
static instance: StellarSorobanCredentials = StellarSorobanCredentials {
type_: ::std::option::Option::None,
address_v2: ::protobuf::MessageField::none(),
+ address_with_delegates: ::protobuf::MessageField::none(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -9582,6 +9973,8 @@ pub mod stellar_soroban_credentials {
SOROBAN_CREDENTIALS_SOURCE_ACCOUNT = 0,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.stellar.StellarSorobanCredentials.StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_V2)
SOROBAN_CREDENTIALS_ADDRESS_V2 = 2,
+ // @@protoc_insertion_point(enum_value:hw.trezor.messages.stellar.StellarSorobanCredentials.StellarSorobanCredentialsType.SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES)
+ SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES = 3,
}
impl ::protobuf::Enum for StellarSorobanCredentialsType {
@@ -9595,6 +9988,7 @@ pub mod stellar_soroban_credentials {
match value {
0 => ::std::option::Option::Some(StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_SOURCE_ACCOUNT),
2 => ::std::option::Option::Some(StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_V2),
+ 3 => ::std::option::Option::Some(StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES),
_ => ::std::option::Option::None
}
}
@@ -9603,13 +9997,15 @@ pub mod stellar_soroban_credentials {
match str {
"SOROBAN_CREDENTIALS_SOURCE_ACCOUNT" => ::std::option::Option::Some(StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_SOURCE_ACCOUNT),
"SOROBAN_CREDENTIALS_ADDRESS_V2" => ::std::option::Option::Some(StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_V2),
+ "SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES" => ::std::option::Option::Some(StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES),
_ => ::std::option::Option::None
}
}
const VALUES: &'static [StellarSorobanCredentialsType] = &[
StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_SOURCE_ACCOUNT,
StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_V2,
+ StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES,
];
}
@@ -9623,6 +10019,7 @@ pub mod stellar_soroban_credentials {
let index = match self {
StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_SOURCE_ACCOUNT => 0,
StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_V2 => 1,
+ StellarSorobanCredentialsType::SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES => 2,
};
Self::enum_descriptor().value_by_index(index)
}
@@ -11342,42 +11739,54 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x18\x02\x20\x02(\x12R\x05nonce\x12>\n\x1bsignature_expiration_ledger\
\x18\x03\x20\x02(\rR\x19signatureExpirationLedger\x12F\n\tsignature\x18\
\x04\x20\x02(\x0b2(.hw.trezor.messages.stellar.StellarSCValR\tsignature\
- \"\xd4\x02\n\x19StellarSorobanCredentials\x12g\n\x04type\x18\x01\x20\x02\
- (\x0e2S.hw.trezor.messages.stellar.StellarSorobanCredentials.StellarSoro\
- banCredentialsTypeR\x04type\x12[\n\naddress_v2\x18\x02\x20\x01(\x0b2<.hw\
- .trezor.messages.stellar.StellarSorobanAddressCredentialsR\taddressV2\"q\
- \n\x1dStellarSorobanCredentialsType\x12&\n\"SOROBAN_CREDENTIALS_SOURCE_A\
- CCOUNT\x10\0\x12\"\n\x1eSOROBAN_CREDENTIALS_ADDRESS_V2\x10\x02\"\x04\x08\
- \x01\x10\x01\"\xe4\x01\n\x20StellarSorobanAuthorizationEntry\x12W\n\x0bc\
- redentials\x18\x01\x20\x02(\x0b25.hw.trezor.messages.stellar.StellarSoro\
- banCredentialsR\x0bcredentials\x12g\n\x0froot_invocation\x18\x02\x20\x02\
- (\x0b2>.hw.trezor.messages.stellar.StellarSorobanAuthorizedInvocationR\
- \x0erootInvocation\"\xe3\x01\n\x1bStellarInvokeHostFunctionOp\x12%\n\x0e\
- source_account\x18\x01\x20\x01(\tR\rsourceAccount\x12K\n\x08function\x18\
- \x02\x20\x02(\x0b2/.hw.trezor.messages.stellar.StellarHostFunctionR\x08f\
- unction\x12P\n\x04auth\x18\x03\x20\x03(\x0b2<.hw.trezor.messages.stellar\
- .StellarSorobanAuthorizationEntryR\x04auth\"\x86\x06\n\x1fStellarSignSor\
- obanAuthorization\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\
- \x12-\n\x12network_passphrase\x18\x02\x20\x02(\tR\x11networkPassphrase\
- \x12\x88\x01\n\renvelope_type\x18\x03\x20\x02(\x0e2c.hw.trezor.messages.\
- stellar.StellarSignSorobanAuthorization.StellarSorobanAuthorizationEnvel\
- opeTypeR\x0cenvelopeType\x12\xaf\x01\n\"soroban_authorization_with_addre\
- ss\x18\x04\x20\x01(\x0b2b.hw.trezor.messages.stellar.StellarSignSorobanA\
- uthorization.StellarSorobanAuthorizationWithAddressR\x1fsorobanAuthoriza\
- tionWithAddress\x1a\xf8\x01\n&StellarSorobanAuthorizationWithAddress\x12\
- \x14\n\x05nonce\x18\x01\x20\x02(\x12R\x05nonce\x12>\n\x1bsignature_expir\
- ation_ledger\x18\x02\x20\x02(\rR\x19signatureExpirationLedger\x12\x18\n\
- \x07address\x18\x03\x20\x02(\tR\x07address\x12^\n\ninvocation\x18\x04\
- \x20\x02(\x0b2>.hw.trezor.messages.stellar.StellarSorobanAuthorizedInvoc\
- ationR\ninvocation\"_\n'StellarSorobanAuthorizationEnvelopeType\x124\n0E\
- NVELOPE_TYPE_SOROBAN_AUTHORIZATION_WITH_ADDRESS\x10\n\"c\n$StellarSoroba\
- nAuthorizationSignature\x12\x1d\n\npublic_key\x18\x01\x20\x02(\x0cR\tpub\
- licKey\x12\x1c\n\tsignature\x18\x02\x20\x02(\x0cR\tsignature\"\x15\n\x13\
- StellarTxExtRequest\"?\n\x0cStellarTxExt\x12\x0c\n\x01v\x18\x01\x20\x02(\
- \x11R\x01v\x12!\n\x0csoroban_data\x18\x02\x20\x01(\x0cR\x0bsorobanData*=\
- \n\x10StellarAssetType\x12\n\n\x06NATIVE\x10\0\x12\r\n\tALPHANUM4\x10\
- \x01\x12\x0e\n\nALPHANUM12\x10\x02B;\n#com.satoshilabs.trezor.lib.protob\
- ufB\x14TrezorMessageStellar\
+ \"\xeb\x01\n\x1fStellarSorobanDelegateSignature\x12\x18\n\x07address\x18\
+ \x01\x20\x02(\tR\x07address\x12F\n\tsignature\x18\x02\x20\x02(\x0b2(.hw.\
+ trezor.messages.stellar.StellarSCValR\tsignature\x12f\n\x10nested_delega\
+ tes\x18\x03\x20\x03(\x0b2;.hw.trezor.messages.stellar.StellarSorobanDele\
+ gateSignatureR\x0fnestedDelegates\"\xf9\x01\n-StellarSorobanAddressCrede\
+ ntialsWithDelegates\x12m\n\x13address_credentials\x18\x01\x20\x02(\x0b2<\
+ .hw.trezor.messages.stellar.StellarSorobanAddressCredentialsR\x12address\
+ Credentials\x12Y\n\tdelegates\x18\x02\x20\x03(\x0b2;.hw.trezor.messages.\
+ stellar.StellarSorobanDelegateSignatureR\tdelegates\"\x86\x04\n\x19Stell\
+ arSorobanCredentials\x12g\n\x04type\x18\x01\x20\x02(\x0e2S.hw.trezor.mes\
+ sages.stellar.StellarSorobanCredentials.StellarSorobanCredentialsTypeR\
+ \x04type\x12[\n\naddress_v2\x18\x02\x20\x01(\x0b2<.hw.trezor.messages.st\
+ ellar.StellarSorobanAddressCredentialsR\taddressV2\x12\x7f\n\x16address_\
+ with_delegates\x18\x03\x20\x01(\x0b2I.hw.trezor.messages.stellar.Stellar\
+ SorobanAddressCredentialsWithDelegatesR\x14addressWithDelegates\"\xa1\
+ \x01\n\x1dStellarSorobanCredentialsType\x12&\n\"SOROBAN_CREDENTIALS_SOUR\
+ CE_ACCOUNT\x10\0\x12\"\n\x1eSOROBAN_CREDENTIALS_ADDRESS_V2\x10\x02\x12.\
+ \n*SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES\x10\x03\"\x04\x08\x01\x10\
+ \x01\"\xe4\x01\n\x20StellarSorobanAuthorizationEntry\x12W\n\x0bcredentia\
+ ls\x18\x01\x20\x02(\x0b25.hw.trezor.messages.stellar.StellarSorobanCrede\
+ ntialsR\x0bcredentials\x12g\n\x0froot_invocation\x18\x02\x20\x02(\x0b2>.\
+ hw.trezor.messages.stellar.StellarSorobanAuthorizedInvocationR\x0erootIn\
+ vocation\"\xe3\x01\n\x1bStellarInvokeHostFunctionOp\x12%\n\x0esource_acc\
+ ount\x18\x01\x20\x01(\tR\rsourceAccount\x12K\n\x08function\x18\x02\x20\
+ \x02(\x0b2/.hw.trezor.messages.stellar.StellarHostFunctionR\x08function\
+ \x12P\n\x04auth\x18\x03\x20\x03(\x0b2<.hw.trezor.messages.stellar.Stella\
+ rSorobanAuthorizationEntryR\x04auth\"\x86\x06\n\x1fStellarSignSorobanAut\
+ horization\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12-\n\
+ \x12network_passphrase\x18\x02\x20\x02(\tR\x11networkPassphrase\x12\x88\
+ \x01\n\renvelope_type\x18\x03\x20\x02(\x0e2c.hw.trezor.messages.stellar.\
+ StellarSignSorobanAuthorization.StellarSorobanAuthorizationEnvelopeTypeR\
+ \x0cenvelopeType\x12\xaf\x01\n\"soroban_authorization_with_address\x18\
+ \x04\x20\x01(\x0b2b.hw.trezor.messages.stellar.StellarSignSorobanAuthori\
+ zation.StellarSorobanAuthorizationWithAddressR\x1fsorobanAuthorizationWi\
+ thAddress\x1a\xf8\x01\n&StellarSorobanAuthorizationWithAddress\x12\x14\n\
+ \x05nonce\x18\x01\x20\x02(\x12R\x05nonce\x12>\n\x1bsignature_expiration_\
+ ledger\x18\x02\x20\x02(\rR\x19signatureExpirationLedger\x12\x18\n\x07add\
+ ress\x18\x03\x20\x02(\tR\x07address\x12^\n\ninvocation\x18\x04\x20\x02(\
+ \x0b2>.hw.trezor.messages.stellar.StellarSorobanAuthorizedInvocationR\ni\
+ nvocation\"_\n'StellarSorobanAuthorizationEnvelopeType\x124\n0ENVELOPE_T\
+ YPE_SOROBAN_AUTHORIZATION_WITH_ADDRESS\x10\n\"c\n$StellarSorobanAuthoriz\
+ ationSignature\x12\x1d\n\npublic_key\x18\x01\x20\x02(\x0cR\tpublicKey\
+ \x12\x1c\n\tsignature\x18\x02\x20\x02(\x0cR\tsignature\"\x15\n\x13Stella\
+ rTxExtRequest\"?\n\x0cStellarTxExt\x12\x0c\n\x01v\x18\x01\x20\x02(\x11R\
+ \x01v\x12!\n\x0csoroban_data\x18\x02\x20\x01(\x0cR\x0bsorobanData*=\n\
+ \x10StellarAssetType\x12\n\n\x06NATIVE\x10\0\x12\r\n\tALPHANUM4\x10\x01\
+ \x12\x0e\n\nALPHANUM12\x10\x02B;\n#com.satoshilabs.trezor.lib.protobufB\
+ \x14TrezorMessageStellar\
";
/// `FileDescriptorProto` object which was a source for this generated file
@@ -11396,7 +11805,7 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
let mut deps = ::std::vec::Vec::with_capacity(1);
deps.push(super::messages_common::file_descriptor().clone());
- let mut messages = ::std::vec::Vec::with_capacity(39);
+ let mut messages = ::std::vec::Vec::with_capacity(41);
messages.push(StellarAsset::generated_message_descriptor_data());
messages.push(StellarGetAddress::generated_message_descriptor_data());
messages.push(StellarAddress::generated_message_descriptor_data());
@@ -11423,6 +11832,8 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
messages.push(StellarSorobanAuthorizedInvocation::generated_message_descriptor_data());
messages.push(StellarHostFunction::generated_message_descriptor_data());
messages.push(StellarSorobanAddressCredentials::generated_message_descriptor_data());
+ messages.push(StellarSorobanDelegateSignature::generated_message_descriptor_data());
+ messages.push(StellarSorobanAddressCredentialsWithDelegates::generated_message_descriptor_data());
messages.push(StellarSorobanCredentials::generated_message_descriptor_data());
messages.push(StellarSorobanAuthorizationEntry::generated_message_descriptor_data());
messages.push(StellarInvokeHostFunctionOp::generated_message_descriptor_data());Why this scored 30/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.