diff --git a/.circleci/config.yml b/.circleci/config.yml index b2d2f49f..034b0e8d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2 defaults: &defaults working_directory: ~/device-protocol docker: - - image: circleci/node + - image: cimg/node:20.11 jobs: build: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..2e901a1e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: Protocol CI + +on: + push: + branches: [master, up/release-protocol] + pull_request: + branches: [master, up/release-protocol] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + + - name: Install protobuf compiler + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install JavaScript generator dependencies + run: npm ci + + - name: Verify install generated JavaScript bindings + run: | + test -s lib/messages_pb.js + test -s lib/messages-solana_pb.js + test -s lib/messages-zcash_pb.js + + - name: Compile protocol descriptors + run: | + protoc --proto_path=. --include_imports \ + --descriptor_set_out=/tmp/keepkey-device-protocol.pb \ + types.proto messages.proto messages-binance.proto \ + messages-cosmos.proto messages-eos.proto messages-ethereum.proto \ + messages-hive.proto messages-mayachain.proto messages-nano.proto \ + messages-osmosis.proto messages-ripple.proto messages-solana.proto \ + messages-tendermint.proto messages-thorchain.proto messages-ton.proto \ + messages-tron.proto messages-zcash.proto + + - name: Check RC18 Zcash wire contract + run: python3 tools/check_zcash_contract.py diff --git a/.github/workflows/copilot-review.yml b/.github/workflows/copilot-review.yml index 54db1498..8afdb03e 100644 --- a/.github/workflows/copilot-review.yml +++ b/.github/workflows/copilot-review.yml @@ -1,11 +1,15 @@ name: Request Copilot Review on: - pull_request: + # This workflow never checks out or executes pull-request code. Using the + # base-repository context is therefore safe and is required for cross-fork + # PRs, whose pull_request GITHUB_TOKEN is always downgraded to read-only. + pull_request_target: types: [opened, reopened, ready_for_review, synchronize] jobs: request-copilot-review: + if: github.event.pull_request.draft == false runs-on: ubuntu-latest permissions: pull-requests: write diff --git a/lib/messages-ripple_pb.d.ts b/lib/messages-ripple_pb.d.ts new file mode 100644 index 00000000..3c47e1ca --- /dev/null +++ b/lib/messages-ripple_pb.d.ts @@ -0,0 +1,179 @@ +// package: +// file: messages-ripple.proto + +import * as jspb from "google-protobuf"; + +export class RippleGetAddress extends jspb.Message { + clearAddressNList(): void; + getAddressNList(): Array; + setAddressNList(value: Array): void; + addAddressN(value: number, index?: number): number; + + hasShowDisplay(): boolean; + clearShowDisplay(): void; + getShowDisplay(): boolean | undefined; + setShowDisplay(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RippleGetAddress.AsObject; + static toObject(includeInstance: boolean, msg: RippleGetAddress): RippleGetAddress.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RippleGetAddress, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RippleGetAddress; + static deserializeBinaryFromReader(message: RippleGetAddress, reader: jspb.BinaryReader): RippleGetAddress; +} + +export namespace RippleGetAddress { + export type AsObject = { + addressNList: Array, + showDisplay?: boolean, + } +} + +export class RippleAddress extends jspb.Message { + hasAddress(): boolean; + clearAddress(): void; + getAddress(): string | undefined; + setAddress(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RippleAddress.AsObject; + static toObject(includeInstance: boolean, msg: RippleAddress): RippleAddress.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RippleAddress, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RippleAddress; + static deserializeBinaryFromReader(message: RippleAddress, reader: jspb.BinaryReader): RippleAddress; +} + +export namespace RippleAddress { + export type AsObject = { + address?: string, + } +} + +export class RippleSignTx extends jspb.Message { + clearAddressNList(): void; + getAddressNList(): Array; + setAddressNList(value: Array): void; + addAddressN(value: number, index?: number): number; + + hasFee(): boolean; + clearFee(): void; + getFee(): number | undefined; + setFee(value: number): void; + + hasFlags(): boolean; + clearFlags(): void; + getFlags(): number | undefined; + setFlags(value: number): void; + + hasSequence(): boolean; + clearSequence(): void; + getSequence(): number | undefined; + setSequence(value: number): void; + + hasLastLedgerSequence(): boolean; + clearLastLedgerSequence(): void; + getLastLedgerSequence(): number | undefined; + setLastLedgerSequence(value: number): void; + + hasPayment(): boolean; + clearPayment(): void; + getPayment(): RipplePayment | undefined; + setPayment(value?: RipplePayment): void; + + hasMemo(): boolean; + clearMemo(): void; + getMemo(): string | undefined; + setMemo(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RippleSignTx.AsObject; + static toObject(includeInstance: boolean, msg: RippleSignTx): RippleSignTx.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RippleSignTx, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RippleSignTx; + static deserializeBinaryFromReader(message: RippleSignTx, reader: jspb.BinaryReader): RippleSignTx; +} + +export namespace RippleSignTx { + export type AsObject = { + addressNList: Array, + fee?: number, + flags?: number, + sequence?: number, + lastLedgerSequence?: number, + payment?: RipplePayment.AsObject, + memo?: string, + } +} + +export class RipplePayment extends jspb.Message { + hasAmount(): boolean; + clearAmount(): void; + getAmount(): number | undefined; + setAmount(value: number): void; + + hasDestination(): boolean; + clearDestination(): void; + getDestination(): string | undefined; + setDestination(value: string): void; + + hasDestinationTag(): boolean; + clearDestinationTag(): void; + getDestinationTag(): number | undefined; + setDestinationTag(value: number): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RipplePayment.AsObject; + static toObject(includeInstance: boolean, msg: RipplePayment): RipplePayment.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RipplePayment, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RipplePayment; + static deserializeBinaryFromReader(message: RipplePayment, reader: jspb.BinaryReader): RipplePayment; +} + +export namespace RipplePayment { + export type AsObject = { + amount?: number, + destination?: string, + destinationTag?: number, + } +} + +export class RippleSignedTx extends jspb.Message { + hasSignature(): boolean; + clearSignature(): void; + getSignature(): Uint8Array | string; + getSignature_asU8(): Uint8Array; + getSignature_asB64(): string; + setSignature(value: Uint8Array | string): void; + + hasSerializedTx(): boolean; + clearSerializedTx(): void; + getSerializedTx(): Uint8Array | string; + getSerializedTx_asU8(): Uint8Array; + getSerializedTx_asB64(): string; + setSerializedTx(value: Uint8Array | string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RippleSignedTx.AsObject; + static toObject(includeInstance: boolean, msg: RippleSignedTx): RippleSignedTx.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: RippleSignedTx, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RippleSignedTx; + static deserializeBinaryFromReader(message: RippleSignedTx, reader: jspb.BinaryReader): RippleSignedTx; +} + +export namespace RippleSignedTx { + export type AsObject = { + signature: Uint8Array | string, + serializedTx: Uint8Array | string, + } +} + diff --git a/lib/messages-ripple_pb.js b/lib/messages-ripple_pb.js new file mode 100644 index 00000000..296100ad --- /dev/null +++ b/lib/messages-ripple_pb.js @@ -0,0 +1,1425 @@ +// source: messages-ripple.proto +/** + * @fileoverview + * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. + * @suppress {messageConventions} JS Compiler reports an error if a variable or + * field starts with 'MSG_' and isn't a translatable message. + * @public + */ +// GENERATED CODE -- DO NOT EDIT! +/* eslint-disable */ +// @ts-nocheck + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = (function() { + if (this) { return this; } + if (typeof window !== 'undefined') { return window; } + if (typeof global !== 'undefined') { return global; } + if (typeof self !== 'undefined') { return self; } + return Function('return this')(); +}.call(null)); + +goog.exportSymbol('proto.RippleAddress', null, global); +goog.exportSymbol('proto.RippleGetAddress', null, global); +goog.exportSymbol('proto.RipplePayment', null, global); +goog.exportSymbol('proto.RippleSignTx', null, global); +goog.exportSymbol('proto.RippleSignedTx', null, global); +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.RippleGetAddress = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.RippleGetAddress.repeatedFields_, null); +}; +goog.inherits(proto.RippleGetAddress, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.RippleGetAddress.displayName = 'proto.RippleGetAddress'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.RippleAddress = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.RippleAddress, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.RippleAddress.displayName = 'proto.RippleAddress'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.RippleSignTx = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.RippleSignTx.repeatedFields_, null); +}; +goog.inherits(proto.RippleSignTx, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.RippleSignTx.displayName = 'proto.RippleSignTx'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.RipplePayment = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.RipplePayment, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.RipplePayment.displayName = 'proto.RipplePayment'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.RippleSignedTx = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.RippleSignedTx, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.RippleSignedTx.displayName = 'proto.RippleSignedTx'; +} + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.RippleGetAddress.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.RippleGetAddress.prototype.toObject = function(opt_includeInstance) { + return proto.RippleGetAddress.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.RippleGetAddress} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleGetAddress.toObject = function(includeInstance, msg) { + var f, obj = { + addressNList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f, + showDisplay: (f = jspb.Message.getBooleanField(msg, 2)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.RippleGetAddress} + */ +proto.RippleGetAddress.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.RippleGetAddress; + return proto.RippleGetAddress.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.RippleGetAddress} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.RippleGetAddress} + */ +proto.RippleGetAddress.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var values = /** @type {!Array} */ (reader.isDelimited() ? reader.readPackedUint32() : [reader.readUint32()]); + for (var i = 0; i < values.length; i++) { + msg.addAddressN(values[i]); + } + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setShowDisplay(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.RippleGetAddress.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.RippleGetAddress.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.RippleGetAddress} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleGetAddress.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAddressNList(); + if (f.length > 0) { + writer.writeRepeatedUint32( + 1, + f + ); + } + f = /** @type {boolean} */ (jspb.Message.getField(message, 2)); + if (f != null) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * repeated uint32 address_n = 1; + * @return {!Array} + */ +proto.RippleGetAddress.prototype.getAddressNList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.RippleGetAddress} returns this + */ +proto.RippleGetAddress.prototype.setAddressNList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {number} value + * @param {number=} opt_index + * @return {!proto.RippleGetAddress} returns this + */ +proto.RippleGetAddress.prototype.addAddressN = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.RippleGetAddress} returns this + */ +proto.RippleGetAddress.prototype.clearAddressNList = function() { + return this.setAddressNList([]); +}; + + +/** + * optional bool show_display = 2; + * @return {boolean} + */ +proto.RippleGetAddress.prototype.getShowDisplay = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.RippleGetAddress} returns this + */ +proto.RippleGetAddress.prototype.setShowDisplay = function(value) { + return jspb.Message.setField(this, 2, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleGetAddress} returns this + */ +proto.RippleGetAddress.prototype.clearShowDisplay = function() { + return jspb.Message.setField(this, 2, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleGetAddress.prototype.hasShowDisplay = function() { + return jspb.Message.getField(this, 2) != null; +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.RippleAddress.prototype.toObject = function(opt_includeInstance) { + return proto.RippleAddress.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.RippleAddress} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleAddress.toObject = function(includeInstance, msg) { + var f, obj = { + address: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.RippleAddress} + */ +proto.RippleAddress.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.RippleAddress; + return proto.RippleAddress.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.RippleAddress} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.RippleAddress} + */ +proto.RippleAddress.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setAddress(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.RippleAddress.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.RippleAddress.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.RippleAddress} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleAddress.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = /** @type {string} */ (jspb.Message.getField(message, 1)); + if (f != null) { + writer.writeString( + 1, + f + ); + } +}; + + +/** + * optional string address = 1; + * @return {string} + */ +proto.RippleAddress.prototype.getAddress = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.RippleAddress} returns this + */ +proto.RippleAddress.prototype.setAddress = function(value) { + return jspb.Message.setField(this, 1, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleAddress} returns this + */ +proto.RippleAddress.prototype.clearAddress = function() { + return jspb.Message.setField(this, 1, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleAddress.prototype.hasAddress = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.RippleSignTx.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.RippleSignTx.prototype.toObject = function(opt_includeInstance) { + return proto.RippleSignTx.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.RippleSignTx} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleSignTx.toObject = function(includeInstance, msg) { + var f, obj = { + addressNList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f, + fee: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f, + flags: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f, + sequence: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f, + lastLedgerSequence: (f = jspb.Message.getField(msg, 5)) == null ? undefined : f, + payment: (f = msg.getPayment()) && proto.RipplePayment.toObject(includeInstance, f), + memo: (f = jspb.Message.getField(msg, 7)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.RippleSignTx} + */ +proto.RippleSignTx.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.RippleSignTx; + return proto.RippleSignTx.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.RippleSignTx} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.RippleSignTx} + */ +proto.RippleSignTx.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var values = /** @type {!Array} */ (reader.isDelimited() ? reader.readPackedUint32() : [reader.readUint32()]); + for (var i = 0; i < values.length; i++) { + msg.addAddressN(values[i]); + } + break; + case 2: + var value = /** @type {number} */ (reader.readUint64()); + msg.setFee(value); + break; + case 3: + var value = /** @type {number} */ (reader.readUint32()); + msg.setFlags(value); + break; + case 4: + var value = /** @type {number} */ (reader.readUint32()); + msg.setSequence(value); + break; + case 5: + var value = /** @type {number} */ (reader.readUint32()); + msg.setLastLedgerSequence(value); + break; + case 6: + var value = new proto.RipplePayment; + reader.readMessage(value,proto.RipplePayment.deserializeBinaryFromReader); + msg.setPayment(value); + break; + case 7: + var value = /** @type {string} */ (reader.readString()); + msg.setMemo(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.RippleSignTx.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.RippleSignTx.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.RippleSignTx} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleSignTx.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAddressNList(); + if (f.length > 0) { + writer.writeRepeatedUint32( + 1, + f + ); + } + f = /** @type {number} */ (jspb.Message.getField(message, 2)); + if (f != null) { + writer.writeUint64( + 2, + f + ); + } + f = /** @type {number} */ (jspb.Message.getField(message, 3)); + if (f != null) { + writer.writeUint32( + 3, + f + ); + } + f = /** @type {number} */ (jspb.Message.getField(message, 4)); + if (f != null) { + writer.writeUint32( + 4, + f + ); + } + f = /** @type {number} */ (jspb.Message.getField(message, 5)); + if (f != null) { + writer.writeUint32( + 5, + f + ); + } + f = message.getPayment(); + if (f != null) { + writer.writeMessage( + 6, + f, + proto.RipplePayment.serializeBinaryToWriter + ); + } + f = /** @type {string} */ (jspb.Message.getField(message, 7)); + if (f != null) { + writer.writeString( + 7, + f + ); + } +}; + + +/** + * repeated uint32 address_n = 1; + * @return {!Array} + */ +proto.RippleSignTx.prototype.getAddressNList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.setAddressNList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {number} value + * @param {number=} opt_index + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.addAddressN = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearAddressNList = function() { + return this.setAddressNList([]); +}; + + +/** + * optional uint64 fee = 2; + * @return {number} + */ +proto.RippleSignTx.prototype.getFee = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.setFee = function(value) { + return jspb.Message.setField(this, 2, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearFee = function() { + return jspb.Message.setField(this, 2, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignTx.prototype.hasFee = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional uint32 flags = 3; + * @return {number} + */ +proto.RippleSignTx.prototype.getFlags = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.setFlags = function(value) { + return jspb.Message.setField(this, 3, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearFlags = function() { + return jspb.Message.setField(this, 3, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignTx.prototype.hasFlags = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional uint32 sequence = 4; + * @return {number} + */ +proto.RippleSignTx.prototype.getSequence = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.setSequence = function(value) { + return jspb.Message.setField(this, 4, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearSequence = function() { + return jspb.Message.setField(this, 4, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignTx.prototype.hasSequence = function() { + return jspb.Message.getField(this, 4) != null; +}; + + +/** + * optional uint32 last_ledger_sequence = 5; + * @return {number} + */ +proto.RippleSignTx.prototype.getLastLedgerSequence = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.setLastLedgerSequence = function(value) { + return jspb.Message.setField(this, 5, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearLastLedgerSequence = function() { + return jspb.Message.setField(this, 5, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignTx.prototype.hasLastLedgerSequence = function() { + return jspb.Message.getField(this, 5) != null; +}; + + +/** + * optional RipplePayment payment = 6; + * @return {?proto.RipplePayment} + */ +proto.RippleSignTx.prototype.getPayment = function() { + return /** @type{?proto.RipplePayment} */ ( + jspb.Message.getWrapperField(this, proto.RipplePayment, 6)); +}; + + +/** + * @param {?proto.RipplePayment|undefined} value + * @return {!proto.RippleSignTx} returns this +*/ +proto.RippleSignTx.prototype.setPayment = function(value) { + return jspb.Message.setWrapperField(this, 6, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearPayment = function() { + return this.setPayment(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignTx.prototype.hasPayment = function() { + return jspb.Message.getField(this, 6) != null; +}; + + +/** + * optional string memo = 7; + * @return {string} + */ +proto.RippleSignTx.prototype.getMemo = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "")); +}; + + +/** + * @param {string} value + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.setMemo = function(value) { + return jspb.Message.setField(this, 7, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignTx} returns this + */ +proto.RippleSignTx.prototype.clearMemo = function() { + return jspb.Message.setField(this, 7, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignTx.prototype.hasMemo = function() { + return jspb.Message.getField(this, 7) != null; +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.RipplePayment.prototype.toObject = function(opt_includeInstance) { + return proto.RipplePayment.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.RipplePayment} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RipplePayment.toObject = function(includeInstance, msg) { + var f, obj = { + amount: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f, + destination: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f, + destinationTag: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.RipplePayment} + */ +proto.RipplePayment.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.RipplePayment; + return proto.RipplePayment.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.RipplePayment} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.RipplePayment} + */ +proto.RipplePayment.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint64()); + msg.setAmount(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setDestination(value); + break; + case 3: + var value = /** @type {number} */ (reader.readUint32()); + msg.setDestinationTag(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.RipplePayment.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.RipplePayment.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.RipplePayment} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RipplePayment.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = /** @type {number} */ (jspb.Message.getField(message, 1)); + if (f != null) { + writer.writeUint64( + 1, + f + ); + } + f = /** @type {string} */ (jspb.Message.getField(message, 2)); + if (f != null) { + writer.writeString( + 2, + f + ); + } + f = /** @type {number} */ (jspb.Message.getField(message, 3)); + if (f != null) { + writer.writeUint32( + 3, + f + ); + } +}; + + +/** + * optional uint64 amount = 1; + * @return {number} + */ +proto.RipplePayment.prototype.getAmount = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.RipplePayment} returns this + */ +proto.RipplePayment.prototype.setAmount = function(value) { + return jspb.Message.setField(this, 1, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RipplePayment} returns this + */ +proto.RipplePayment.prototype.clearAmount = function() { + return jspb.Message.setField(this, 1, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RipplePayment.prototype.hasAmount = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional string destination = 2; + * @return {string} + */ +proto.RipplePayment.prototype.getDestination = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.RipplePayment} returns this + */ +proto.RipplePayment.prototype.setDestination = function(value) { + return jspb.Message.setField(this, 2, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RipplePayment} returns this + */ +proto.RipplePayment.prototype.clearDestination = function() { + return jspb.Message.setField(this, 2, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RipplePayment.prototype.hasDestination = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional uint32 destination_tag = 3; + * @return {number} + */ +proto.RipplePayment.prototype.getDestinationTag = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.RipplePayment} returns this + */ +proto.RipplePayment.prototype.setDestinationTag = function(value) { + return jspb.Message.setField(this, 3, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RipplePayment} returns this + */ +proto.RipplePayment.prototype.clearDestinationTag = function() { + return jspb.Message.setField(this, 3, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RipplePayment.prototype.hasDestinationTag = function() { + return jspb.Message.getField(this, 3) != null; +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.RippleSignedTx.prototype.toObject = function(opt_includeInstance) { + return proto.RippleSignedTx.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.RippleSignedTx} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleSignedTx.toObject = function(includeInstance, msg) { + var f, obj = { + signature: msg.getSignature_asB64(), + serializedTx: msg.getSerializedTx_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.RippleSignedTx} + */ +proto.RippleSignedTx.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.RippleSignedTx; + return proto.RippleSignedTx.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.RippleSignedTx} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.RippleSignedTx} + */ +proto.RippleSignedTx.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setSignature(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setSerializedTx(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.RippleSignedTx.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.RippleSignedTx.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.RippleSignedTx} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.RippleSignedTx.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = /** @type {!(string|Uint8Array)} */ (jspb.Message.getField(message, 1)); + if (f != null) { + writer.writeBytes( + 1, + f + ); + } + f = /** @type {!(string|Uint8Array)} */ (jspb.Message.getField(message, 2)); + if (f != null) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional bytes signature = 1; + * @return {!(string|Uint8Array)} + */ +proto.RippleSignedTx.prototype.getSignature = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes signature = 1; + * This is a type-conversion wrapper around `getSignature()` + * @return {string} + */ +proto.RippleSignedTx.prototype.getSignature_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getSignature())); +}; + + +/** + * optional bytes signature = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getSignature()` + * @return {!Uint8Array} + */ +proto.RippleSignedTx.prototype.getSignature_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getSignature())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.RippleSignedTx} returns this + */ +proto.RippleSignedTx.prototype.setSignature = function(value) { + return jspb.Message.setField(this, 1, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignedTx} returns this + */ +proto.RippleSignedTx.prototype.clearSignature = function() { + return jspb.Message.setField(this, 1, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignedTx.prototype.hasSignature = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional bytes serialized_tx = 2; + * @return {!(string|Uint8Array)} + */ +proto.RippleSignedTx.prototype.getSerializedTx = function() { + return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes serialized_tx = 2; + * This is a type-conversion wrapper around `getSerializedTx()` + * @return {string} + */ +proto.RippleSignedTx.prototype.getSerializedTx_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getSerializedTx())); +}; + + +/** + * optional bytes serialized_tx = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getSerializedTx()` + * @return {!Uint8Array} + */ +proto.RippleSignedTx.prototype.getSerializedTx_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getSerializedTx())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.RippleSignedTx} returns this + */ +proto.RippleSignedTx.prototype.setSerializedTx = function(value) { + return jspb.Message.setField(this, 2, value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.RippleSignedTx} returns this + */ +proto.RippleSignedTx.prototype.clearSerializedTx = function() { + return jspb.Message.setField(this, 2, undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.RippleSignedTx.prototype.hasSerializedTx = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +goog.object.extend(exports, proto); diff --git a/messages-ethereum.options b/messages-ethereum.options index 1759d0ac..fa1767f5 100644 --- a/messages-ethereum.options +++ b/messages-ethereum.options @@ -1,2 +1,14 @@ EthereumTxMetadata.signed_payload max_size:1024 EthereumMetadataAck.display_summary max_size:32 +LoadClearsignSigner.pubkey max_size:33 +LoadClearsignSigner.alias max_size:32 +LoadClearsignSigner.icon max_size:384 + +EthereumSignTypedData.primary_type max_size:80 +EthereumTypedDataStructRequest.name max_size:80 +EthereumTypedDataStructAck.members max_count:32 +EthereumTypedDataStructAck.EthereumStructMember.name max_size:64 +EthereumTypedDataStructAck.EthereumFieldType.struct_name max_size:80 +EthereumTypedDataStructAck.EthereumFieldType.array_levels max_count:4 +EthereumTypedDataValueRequest.member_path max_count:16 +EthereumTypedDataValueAck.value max_size:1024 diff --git a/messages-ethereum.proto b/messages-ethereum.proto index b8719d34..7a708b41 100644 --- a/messages-ethereum.proto +++ b/messages-ethereum.proto @@ -113,6 +113,66 @@ message EthereumMetadataAck { optional string display_summary = 2; // Brief result for host logging } +/** + * Request: Load a clearsign signer public key + alias into a key slot. + * The device shows a mandatory confirmation (alias + key fingerprint) before + * accepting; there is no way to load a signer without user consent. + * A signer is RAM-only and is cleared on reboot. The persist field is retained + * for wire compatibility and future authenticated storage; firmware 7.15 + * rejects persist=true. Every transaction whose metadata was verified by a loaded + * (non built-in) signer is preceded by a warning screen naming the alias + * during transaction confirmation. + * @next Success + * @next Failure + */ +message LoadClearsignSigner { + optional uint32 key_id = 1; // target key slot (0-3); must not hold a built-in key + optional bytes pubkey = 2; // 33-byte compressed secp256k1 public key + optional string alias = 3; // short display name shown on load confirm + per-tx warning + /* + * Optional identity logo, <= 384 bytes, run-length encoded — NOT a packed + * bitmap. (This is the format because draw_bitmap_mono_rle() is the decoder + * of record and every bundled image already uses it; it is NOT a size + * workaround — a packed 1bpp icon at the legal maximum geometry, 40x64, + * would be 320 bytes and would fit the cap.) + * Pixels are BYTE-VALUED intensity, one byte per pixel after decoding; the + * device renders each as (value * color / 100). Decoder of record: + * keepkey-firmware lib/board/draw.c: draw_bitmap_mono_rle(). + * + * Grammar — the stream is a sequence of packets. Read n = (int8)data[i++]: + * n in [1, 127] RUN : one value byte follows; emit it n times. [n][v] + * n in [-127, -1] LITERAL : (-n) value bytes follow; emit each once. [n][v1]..[v-n] + * n == 0 : invalid. + * n == -128 (0x80) : INVALID. The decoder's run counter is int8_t, + * so it cannot represent -(-128) = 128; a 0x80 + * packet is undecodable. Encoders MUST split a + * 128-byte literal into two packets. Firmware + * rejects 0x80 rather than rendering. + * The stream must decode EXACTLY, and the device validates this before the + * icon is shown or stored: no run may straddle the end of the image, + * exactly icon_width*icon_height pixels are emitted (row-major, + * left->right, top->bottom), and the ENTIRE input must be consumed — + * trailing packets after the final pixel are rejected. So a RUN emits at + * most 127 pixels and a LITERAL at most 127. + * + * Golden vector (2x2, w=2 h=2): bytes 03 FF FF 00 + * 03 -> RUN of 3, value FF => pixels [FF, FF, FF] + * FF -> n = -1, LITERAL of 1 => next byte 00 => pixel [00] + * decoded = FF FF FF 00 (row0 = FF FF, row1 = FF 00) + */ + optional bytes icon = 4; + /* + * Icon pixel width, 1..40. The cap is the confirm screen's left icon column + * (LEFT_MARGIN_WITH_ICON = 40); title/body text begins at x=40 and the icon + * is drawn AFTER the text, so a wider icon would paint over the alias, + * fingerprint and the "NOT verified by KeepKey" warning on the trust screen. + * Icon + both dimensions omitted => text-only identity. + */ + optional uint32 icon_width = 5; + optional uint32 icon_height = 6; // icon pixel height (1..64; the icon column is 64px tall) + optional bool persist = 7; // reserved compatibility field; firmware rejects true (RAM-only) +} + //////////////////////////////////////// // Ethereum: Message signing messages // //////////////////////////////////////// @@ -187,3 +247,132 @@ message Ethereum712TypesValues { required string eip712data = 4; // "domain" or "message" json string (up to 2048) required uint32 eip712typevals = 5; // device calculates hash for 1 = domain sep, 2 = message } + +// ── Structured EIP-712, device-driven field streaming ──────────────── +// +// The device drives. It asks for one type definition, or one leaf VALUE, at a +// time, and hashes each value in the same pass that displays it. The host owns +// the document; the device holds only the digest stack for the containers +// currently open, so a 10,000-element array costs the same RAM as a 2-element +// one and there is no document-size limit to raise later. +// +// This replaces Ethereum712TypesValues, which shipped the whole document in two +// 2048-byte JSON blobs and was withdrawn in 7.14.2: its parser could not +// guarantee that the value shown on screen was the value being hashed. Here +// that property is structural -- a value is displayed and absorbed from the +// same buffer in the same call, and each member_path is requested exactly once. +// +// Shapes follow Trezor's where they can, so a host that can drive a Trezor can +// drive a KeepKey with the same traversal logic. ONE deliberate divergence is +// described at EthereumFieldType. + +/** + * Request: Begin structured EIP-712 signing. The device replies with + * EthereumTypedDataStructRequest and drives from there. + * @start + * @next EthereumTypedDataStructRequest + * @next Failure + */ +message EthereumSignTypedData { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + required string primary_type = 2; // primaryType of the message being signed + optional bool metamask_v4_compat = 3 [default = true]; // array-of-struct hashing follows MetaMask v4 +} + +/** + * Response: The device needs this struct's member list before it can hash. + * @next EthereumTypedDataStructAck + */ +message EthereumTypedDataStructRequest { + required string name = 1; // struct name, "EIP712Domain" for the domain +} + +/** + * Request: The member list for the struct the device just asked about, in + * declaration order. Order is part of the signature: it determines encodeType + * and the order encodeData concatenates members. + * @next EthereumTypedDataStructRequest + * @next EthereumTypedDataValueRequest + * @next Failure + */ +message EthereumTypedDataStructAck { + repeated EthereumStructMember members = 1; + + message EthereumStructMember { + required EthereumFieldType type = 1; + required string name = 2; + } + + /** + * DIVERGENCE FROM TREZOR, and the reason for it. + * + * Trezor and OneKey describe an array as a field whose `entry_type` is + * another EthereumFieldType -- a self-referential message. Trezor can do + * that because core is Python. OneKey does it on nanopb by compiling that + * one field as a POINTER, which needs PB_ENABLE_MALLOC, and then flattens + * the pointer chain into a fixed pool to sever the recursion. + * + * KeepKey's nanopb is static-allocation only, and a heap inside a signing + * device is a liability we are not taking on for one field. So the array + * nesting is FLATTENED onto the wire, the way Ledger describes it: + * data_type is always the LEAF type, and array_levels carries the + * dimensions. + * + * array_levels lists the bracket groups in the order they are written in + * the Solidity type string, left to right -- which is the order encodeType + * must reproduce. 0 means a dynamic dimension, N means a fixed one: + * + * uint256 -> data_type=UINT, size=32, array_levels=[] + * address[] -> data_type=ADDRESS, array_levels=[0] + * Person[3] -> data_type=STRUCT, struct_name="Person", + * array_levels=[3] + * int16[2][][4] -> data_type=INT, size=2, array_levels=[2,0,4] + * + * Nothing EIP-712 permits is lost, and the encoding is bounded, flat and + * statically sized. + */ + message EthereumFieldType { + required EthereumDataType data_type = 1; // the LEAF type; never ARRAY + optional uint32 size = 2; // bytesN: N. intN/uintN: N in BYTES, 1..32. + optional string struct_name = 3; // STRUCT: its name, to request in turn + repeated uint32 array_levels = 4; // see above. Empty for a non-array. + } + + // Values match Trezor's enum so a shared host implementation keeps its + // mapping. ARRAY is reserved and never sent -- see EthereumFieldType. + enum EthereumDataType { + UINT = 1; + INT = 2; + BYTES = 3; + STRING = 4; + BOOL = 5; + ADDRESS = 6; + ARRAY = 7; // reserved, unused + STRUCT = 8; + } +} + +/** + * Response: The device needs one leaf value. member_path addresses it: element + * 0 is 0 for the domain and 1 for the message, and the rest index members and + * array elements from there. A struct is never requested as a value -- the + * device walks into it. An array's LENGTH is requested as its own value, big + * endian uint16, before its elements. + * @next EthereumTypedDataValueAck + */ +message EthereumTypedDataValueRequest { + repeated uint32 member_path = 1; +} + +/** + * Request: The raw big-endian bytes of the requested leaf, already the exact + * declared width. Not JSON: the device does no number parsing, so there is no + * integer width ceiling and no decimal-to-binary step that could disagree with + * what the host meant. + * @next EthereumTypedDataValueRequest + * @next EthereumTypedDataSignature + * @next Failure + */ +message EthereumTypedDataValueAck { + required bytes value = 1; +} diff --git a/messages-hive.options b/messages-hive.options new file mode 100644 index 00000000..d39d5921 --- /dev/null +++ b/messages-hive.options @@ -0,0 +1,58 @@ +HiveGetPublicKey.address_n max_count:8 + +HivePublicKey.public_key max_size:64 +HivePublicKey.raw_public_key max_size:33 + +HiveGetPublicKeys.account_index int_size:IS_32 + +HivePublicKeys.owner_key max_size:64 +HivePublicKeys.active_key max_size:64 +HivePublicKeys.memo_key max_size:64 +HivePublicKeys.posting_key max_size:64 + +HiveSignTx.address_n max_count:8 +HiveSignTx.chain_id max_size:32 +HiveSignTx.from max_size:16 +HiveSignTx.to max_size:16 +HiveSignTx.amount int_size:IS_64 +HiveSignTx.asset_symbol max_size:10 +HiveSignTx.memo max_size:2048 + +HiveSignedTx.signature max_size:65 +HiveSignedTx.serialized_tx max_size:512 + +HiveSignAccountCreate.address_n max_count:8 +HiveSignAccountCreate.chain_id max_size:32 +HiveSignAccountCreate.creator max_size:16 +HiveSignAccountCreate.new_account_name max_size:16 +HiveSignAccountCreate.owner_key max_size:64 +HiveSignAccountCreate.active_key max_size:64 +HiveSignAccountCreate.posting_key max_size:64 +HiveSignAccountCreate.memo_key max_size:64 +HiveSignAccountCreate.fee_amount int_size:IS_64 + +HiveSignedAccountCreate.signature max_size:65 +HiveSignedAccountCreate.serialized_tx max_size:512 + +HiveSignAccountUpdate.address_n max_count:8 +HiveSignAccountUpdate.chain_id max_size:32 +HiveSignAccountUpdate.account max_size:16 +HiveSignAccountUpdate.new_owner_key max_size:64 +HiveSignAccountUpdate.new_active_key max_size:64 +HiveSignAccountUpdate.new_posting_key max_size:64 +HiveSignAccountUpdate.new_memo_key max_size:64 + +HiveSignedAccountUpdate.signature max_size:65 +HiveSignedAccountUpdate.serialized_tx max_size:512 + +HiveSignMessage.address_n max_count:8 +HiveSignMessage.message max_size:1024 + +HiveSignedMessage.signature max_size:65 +HiveSignedMessage.public_key max_size:33 + +HiveSignOperations.address_n max_count:8 +HiveSignOperations.chain_id max_size:32 +HiveSignOperations.serialized_tx max_size:2048 + +HiveSignedOperations.signature max_size:65 diff --git a/messages-hive.proto b/messages-hive.proto new file mode 100644 index 00000000..83f06abf --- /dev/null +++ b/messages-hive.proto @@ -0,0 +1,220 @@ +syntax = "proto2"; + +option java_package = "com.shapeshift.keepkey.lib.protobuf"; +option java_outer_classname = "KeepKeyMessageHive"; + +/** + * Request: Ask device for a single Hive public key at a given SLIP-0048 path. + * Path format: m/48'/13'/role'/account'/0' + * role: 0'=owner 1'=active 3'=memo 4'=posting + * @start + * @next HivePublicKey + * @next Failure + */ +message HiveGetPublicKey { + repeated uint32 address_n = 1; // Full SLIP-0048 path (all 5 components hardened) + optional bool show_display = 2; // Confirm on device before returning + optional uint32 role = 3; // 0=owner 1=active 3=memo 4=posting (for display label only) +} + +/** + * Response: Single Hive public key + * @end + */ +message HivePublicKey { + optional string public_key = 1; // STM-prefixed base58check public key + optional bytes raw_public_key = 2; // 33-byte compressed secp256k1 public key +} + +/** + * Request: Ask device for all four Hive role keys in one interaction. + * Derives owner/active/memo/posting keys for the given account index. + * Paths: + * owner: m/48'/13'/0'/account_index'/0' + * active: m/48'/13'/1'/account_index'/0' + * memo: m/48'/13'/3'/account_index'/0' + * posting: m/48'/13'/4'/account_index'/0' + * @start + * @next HivePublicKeys + * @next Failure + */ +message HiveGetPublicKeys { + optional uint32 account_index = 1 [default = 0]; // Hive account slot (0 = first account) + optional bool show_display = 2; // Confirm on device before returning +} + +/** + * Response: All four Hive role public keys + * @end + */ +message HivePublicKeys { + optional string owner_key = 1; // STM... owner public key + optional string active_key = 2; // STM... active public key + optional string memo_key = 3; // STM... memo public key + optional string posting_key = 4; // STM... posting public key +} + +/** + * Request: Sign a Hive transfer transaction (op type 2). + * Signing key should be the active key: m/48'/13'/1'/account'/0' + * @start + * @next HiveSignedTx + * @next Failure + */ +message HiveSignTx { + repeated uint32 address_n = 1; // Full SLIP-0048 path of signing key + optional bytes chain_id = 2; // 32-byte chain ID (mainnet = beeab0de...) + optional uint32 ref_block_num = 3; // Reference block number (uint16) + optional uint32 ref_block_prefix = 4; // Reference block prefix (uint32) + optional uint32 expiration = 5; // Expiration Unix timestamp (uint32) + optional string from = 6; // Sender account name + optional string to = 7; // Recipient account name + optional uint64 amount = 8; // Amount in milliHIVE (1000 = 1.000 HIVE) + optional uint32 decimals = 9; // Decimal places (3 for HIVE/HBD) + optional string asset_symbol = 10; // "HIVE" or "HBD" + optional string memo = 11; // Optional transfer memo +} + +/** + * Response: Signed Hive transfer transaction + * @end + */ +message HiveSignedTx { + optional bytes signature = 1; // 65-byte recoverable secp256k1 signature + optional bytes serialized_tx = 2; // Serialized Graphene transaction bytes +} + +/** + * Request: ATTEST to a Hive account_create operation (op type 9). + * + * NOT a broadcast signature. In Hive, account_create is authorized by the + * CREATOR (sponsor) account's ACTIVE authority — which the new account holder + * does not have. The device instead signs the account_create bytes with the new + * account's OWNER key as a proof-of-control attestation (confirmed on-device). + * The sponsor recovers the owner pubkey from this signature to verify control, + * then rebuilds and signs the real account_create with the creator's active key + * server-side and broadcasts that. The serialized_tx/signature returned here are + * attestation material, not a broadcastable transaction. + * + * All four role public keys become the account authorities at genesis; no + * software keys are generated (KeepKey is sole root of trust from block 1). + * Attestation signing key: owner key at m/48'/13'/0'/account_index'/0' + * Request: Sign a Hive account_create operation (op type 9). + * All four role public keys become the account authorities at genesis. + * No software keys are generated. KeepKey is sole root of trust from block 1. + * Signing key: owner key at m/48'/13'/0'/account_index'/0' + * @start + * @next HiveSignedAccountCreate + * @next Failure + */ +message HiveSignAccountCreate { + repeated uint32 address_n = 1; // Owner key path (m/48'/13'/0'/account'/0') + optional bytes chain_id = 2; // 32-byte chain ID + optional uint32 ref_block_num = 3; + optional uint32 ref_block_prefix = 4; + optional uint32 expiration = 5; + optional string creator = 6; // Pioneer sponsor account name + optional string new_account_name = 7; // Desired Hive username + optional string owner_key = 8; // STM... owner public key (from device) + optional string active_key = 9; // STM... active public key (from device) + optional string posting_key = 10; // STM... posting public key (from device) + optional string memo_key = 11; // STM... memo public key (from device) + optional uint64 fee_amount = 12; // Creation fee in milliHIVE (3000 = 3.000 HIVE) +} + +/** + * Response: Signed Hive account_create transaction + * @end + */ +message HiveSignedAccountCreate { + optional bytes signature = 1; // 65-byte recoverable signature + optional bytes serialized_tx = 2; // Serialized Graphene transaction bytes +} + +/** + * Request: Sign a Hive account_update operation (op type 10). + * Replaces all account authorities with KeepKey-derived keys. + * Used to secure an existing Hive account. + * Signing key: owner key at m/48'/13'/0'/account_index'/0' + * @start + * @next HiveSignedAccountUpdate + * @next Failure + */ +message HiveSignAccountUpdate { + repeated uint32 address_n = 1; // Owner key path (must match account's current owner) + optional bytes chain_id = 2; // 32-byte chain ID + optional uint32 ref_block_num = 3; + optional uint32 ref_block_prefix = 4; + optional uint32 expiration = 5; + optional string account = 6; // Hive account name to update + optional string new_owner_key = 7; // STM... new owner public key + optional string new_active_key = 8; // STM... new active public key + optional string new_posting_key = 9; // STM... new posting public key + optional string new_memo_key = 10; // STM... new memo public key +} + +/** + * Response: Signed Hive account_update transaction + * @end + */ +message HiveSignedAccountUpdate { + optional bytes signature = 1; // 65-byte recoverable signature + optional bytes serialized_tx = 2; // Serialized Graphene transaction bytes +} + +/** + * Request: Sign an arbitrary message with a Hive role key. + * Implements the Hive Keychain requestSignBuffer contract (hive-js + * Signature.signBuffer): signature over SHA256(message bytes) — a single + * hash of the raw bytes only, NO chain_id prepend (unlike transactions) + * and NO Bitcoin/Solana-style message prefix. This is the Hive dApp login + * primitive (Aioha / Keychain SDK). + * Signing key: posting/active/memo role (Keychain's requestSignBuffer + * surface — owner' is rejected); dApp login uses posting + * (m/48'/13'/4'/account'/0'). + * @start + * @next HiveSignedMessage + * @next Failure + */ +message HiveSignMessage { + repeated uint32 address_n = 1; // Full SLIP-0048 path of signing key + optional bytes message = 2; // Raw message bytes (max 1024) +} + +/** + * Response: Signed Hive message + * @end + */ +message HiveSignedMessage { + optional bytes signature = 1; // 65-byte recoverable secp256k1 signature (27+recid+4, r, s) + optional bytes public_key = 2; // 33-byte compressed public key of the signing key +} + +/** + * Request: Sign a host-serialized Graphene transaction after parsing and + * clear-signing every operation in it. The firmware re-derives everything it + * displays from the bytes themselves; transactions containing operations + * outside the supported table are refused (no blind-sign fallback). + * Phase-1 table: vote (0), comment (1), custom_json (18). + * Op types 2/9/10 (transfer, account_create, account_update) are PERMANENTLY + * excluded — they keep their dedicated message types and invariants. + * Signing key: posting (m/48'/13'/4'/account'/0') for posting-tier txs, + * active (m/48'/13'/1'/account'/0') when custom_json carries required_auths. + * Digest: SHA256(chain_id || serialized_tx), same as HiveSignTx. + * @start + * @next HiveSignedOperations + * @next Failure + */ +message HiveSignOperations { + repeated uint32 address_n = 1; // Full SLIP-0048 path of signing key + optional bytes chain_id = 2; // 32-byte chain ID (mainnet = beeab0de...) + optional bytes serialized_tx = 3; // Graphene tx bytes: header..extensions, NO chain_id prefix (max 2048) +} + +/** + * Response: Signed Hive operations transaction + * @end + */ +message HiveSignedOperations { + optional bytes signature = 1; // 65-byte recoverable secp256k1 signature (27+recid+4, r, s) +} diff --git a/messages-near.proto b/messages-near.proto new file mode 100644 index 00000000..c44b04dc --- /dev/null +++ b/messages-near.proto @@ -0,0 +1,60 @@ +/* + * Messages (NEAR Protocol) for KeepKey Communication + * + * NEAR native account support via Ed25519 on the device. + * Derivation path: m/44'/397'/0' (SLIP-0010 hardened-only) + * Address: lowercase hex of 32-byte Ed25519 public key (implicit account) + * Signing: Ed25519(SHA256(borsh_serialized_transaction)) + */ + +syntax = "proto2"; + +option java_package = "com.keepkey.deviceprotocol"; +option java_outer_classname = "KeepKeyMessageNear"; + +/** + * Request: Derive NEAR implicit account address at the given path + * @next NearAddress + * @next Failure + */ +message NearGetAddress { + repeated uint32 address_n = 1; // BIP-44 path (e.g. m/44'/397'/0') + optional string coin_name = 2 [default = "NEAR"]; + optional bool show_display = 3; +} + +/** + * Response: NEAR implicit account address (lowercase hex of Ed25519 pubkey) + * @prev NearGetAddress + */ +message NearAddress { + optional string address = 1; // lowercase hex of 32-byte Ed25519 pubkey + optional bytes public_key = 2; // Raw 32-byte Ed25519 pubkey +} + +/** + * Request: Sign a NEAR transaction + * + * The host Borsh-serializes the full NearTransaction and sends raw bytes. + * Firmware SHA256-hashes the bytes, signs with Ed25519, returns 64-byte signature. + * receiver_id and action_display are provided separately for on-screen confirmation. + * + * @next NearSignedTx + * @next Failure + */ +message NearSignTx { + repeated uint32 address_n = 1; // BIP-44 path to signing key + optional string coin_name = 2 [default = "NEAR"]; + optional bytes raw_tx = 3; // Borsh-serialized NearTransaction (max 1024 bytes) + optional string receiver_id = 4; // Destination account for display (max 64 chars) + optional string action_display = 5; // Human-readable action summary for display +} + +/** + * Response: Ed25519 signature over SHA256(raw_tx) + * @prev NearSignTx + */ +message NearSignedTx { + optional bytes signature = 1; // 64-byte Ed25519 signature + optional bytes public_key = 2; // 32-byte Ed25519 pubkey (for verification) +} diff --git a/messages-ripple.proto b/messages-ripple.proto index 0fc012d2..bf526ef7 100644 --- a/messages-ripple.proto +++ b/messages-ripple.proto @@ -34,6 +34,7 @@ message RippleSignTx { optional uint32 sequence = 4; // transaction sequence number optional uint32 last_ledger_sequence = 5; // see https://developers.ripple.com/reliable-transaction-submission.html#lastledgersequence optional RipplePayment payment = 6; // Payment transaction type + optional string memo = 7; // transaction memo (e.g. THORChain swap routing memo) } /** diff --git a/messages-solana.options b/messages-solana.options index ee812da1..fd945238 100644 --- a/messages-solana.options +++ b/messages-solana.options @@ -4,6 +4,10 @@ SolanaSignTx.address_n max_count:8 SolanaSignTx.coin_name max_size:21 SolanaSignTx.raw_tx max_size:1232 SolanaSignTx.token_info max_count:4 +SolanaSignTx.schema_payload max_size:256 +SolanaSignTx.schema_signature max_size:64 +SolanaSignTx.token_recipient_owner max_count:4 +SolanaSignTx.token_recipient_owner max_size:32 SolanaTokenInfo.mint max_size:32 SolanaTokenInfo.symbol max_size:13 SolanaAddress.address max_size:45 diff --git a/messages-solana.proto b/messages-solana.proto index a8f4eea2..312b1481 100644 --- a/messages-solana.proto +++ b/messages-solana.proto @@ -37,6 +37,13 @@ message SolanaTokenInfo { optional bytes mint = 1; // 32-byte mint public key optional string symbol = 2; // Token symbol e.g. "USDC" (max 12) optional uint32 decimals = 3; // Token decimals e.g. 6 + // Optional attestation: ECDSA(secp256k1) signature over a domain-separated + // digest of (mint, decimals, symbol), signed by a clear-sign signer the + // user loaded via LoadClearsignSigner. When present and valid, the device + // trusts the symbol; when absent it falls back to displaying the raw mint. + // (Firmware verifies; the host/SDK signing side is a follow-up.) + optional bytes signature = 4; // 64-byte compact ECDSA signature + optional uint32 signer_key_id = 5; // which loaded clear-sign signer } /** @@ -49,6 +56,64 @@ message SolanaSignTx { optional string coin_name = 2 [default = "Solana"]; optional bytes raw_tx = 3; // Serialized Solana transaction bytes repeated SolanaTokenInfo token_info = 4; // Token metadata for display (max 4) + /* + * KKSOLSW1 -- transaction-bound account attestation. + * + * A Solana v0 transaction may source instruction accounts from an Address + * Lookup Table. Those accounts are NOT in the bytes being signed, so the + * device cannot derive them and refuses to guess: such a transaction is + * forced to SOL_TX_REVIEW_OPAQUE, which is refused outright unless the user + * has enabled AdvancedMode and is then an explicit BLIND SIGN. The + * instruction's meaning is never shown. + * + * So this does not rescue a blank screen -- it upgrades a blind sign into a + * provider-attested clear sign, which is the whole point of the tier. + * + * A provider may attest the resolved account list for THIS transaction. + * The attestation is bound to the exact message hash, so it cannot be + * replayed onto another transaction, and it is domain-tagged so a + * signature made for any other purpose cannot be replayed as one. + * + * This is annotation, not authority: the accounts are displayed as + * PROVIDER-ATTESTED alongside the provider's alias, and the normal + * unverified-transaction review still runs. Rendering nothing while + * signing is the outcome this replaces. + * + * Preimage: "KeepKeySolanaTxAccounts/1" || message_hash(32) + * || count(le32) || account[0..count-1] (32 bytes each) + */ + repeated bytes lut_account = 5; // resolved 32-byte account keys (max 8) + optional bytes lut_signature = 6; // 64-byte compact secp256k1 over SHA256(preimage) + optional uint32 lut_signer_key_id = 7; // trusted clearsign signer slot (0-3) + // Still reserved: one-request opaque-signing consent. + reserved 8; + /* + * KKSOLSC1 instruction schema (see solana.h). A schema describes how to + * read ONE program instruction: program id, discriminator, and the + * labelled args/accounts to display. It carries no amounts and no + * transaction hash, so a signer attests it ONCE per program+instruction + * and every later transaction reuses it — the device decodes the values + * out of the raw_tx bytes it is about to sign. + * + * Safety comes from structural completeness rather than binding to one + * transaction: firmware requires the schema to account for the + * instruction data exactly, and every other instruction in the + * transaction to be a program it already recognises. Runtime-loaded + * signers are annotation-only, so the normal Advanced-mode unverified + * transaction warning remains additive. + */ + optional bytes schema_payload = 9; + optional bytes schema_signature = 10; // 64-byte compact secp256k1 over SHA256(payload) + optional uint32 schema_signer_key_id = 11; // trusted clearsign signer slot (0-3) + /* + * Candidate owners for SPL associated-token-account destinations. For a + * TransferChecked instruction, firmware may display an owner only after + * independently deriving ATA(owner, token_program, mint) and matching it + * to the signed destination account. An unmatched candidate is never + * treated as a recipient. This lets payment protocols such as x402 show + * their payTo address without trusting host-side decoding or chain RPC. + */ + repeated bytes token_recipient_owner = 12; // 32-byte Solana public keys (max 4) } /** diff --git a/messages-thorchain.proto b/messages-thorchain.proto index acde357a..00183623 100644 --- a/messages-thorchain.proto +++ b/messages-thorchain.proto @@ -60,6 +60,7 @@ message ThorchainMsgSend { optional uint64 amount = 8 [jstype = JS_STRING]; optional OutputAddressType address_type = 9; reserved 10; + optional string denom = 11; // asset denom, e.g. "rune" or IBC denom } message ThorchainMsgDeposit { diff --git a/messages-zcash.options b/messages-zcash.options index 89fcdc36..4ab6a997 100644 --- a/messages-zcash.options +++ b/messages-zcash.options @@ -5,6 +5,8 @@ ZcashSignPCZT.transparent_digest max_size:32 ZcashSignPCZT.sapling_digest max_size:32 ZcashSignPCZT.orchard_digest max_size:32 ZcashSignPCZT.orchard_anchor max_size:32 +ZcashSignPCZT.ironwood_digest max_size:32 +ZcashSignPCZT.expected_seed_fingerprint max_size:32 ZcashPCZTAction.alpha max_size:32 ZcashPCZTAction.sighash max_size:32 @@ -17,6 +19,8 @@ ZcashPCZTAction.enc_memo max_size:512 ZcashPCZTAction.enc_noncompact max_size:612 ZcashPCZTAction.rk max_size:32 ZcashPCZTAction.out_ciphertext max_size:80 +ZcashPCZTAction.recipient max_size:43 +ZcashPCZTAction.rseed max_size:32 ZcashSignedPCZT.signatures max_count:64 max_size:64 ZcashSignedPCZT.txid max_size:32 @@ -26,16 +30,19 @@ ZcashGetOrchardFVK.address_n max_count:8 ZcashOrchardFVK.ak max_size:32 ZcashOrchardFVK.nk max_size:32 ZcashOrchardFVK.rivk max_size:32 +ZcashOrchardFVK.seed_fingerprint max_size:32 + +ZcashTransparentOutput.script_pubkey max_size:128 ZcashTransparentInput.sighash max_size:32 ZcashTransparentInput.address_n max_count:8 +ZcashTransparentInput.prevout_txid max_size:32 +ZcashTransparentInput.script_pubkey max_size:128 -ZcashTransparentSig.signature max_size:73 +ZcashTransparentSigned.signatures max_count:8 max_size:73 ZcashDisplayAddress.address_n max_count:8 -ZcashDisplayAddress.address max_size:256 -ZcashDisplayAddress.ak max_size:32 -ZcashDisplayAddress.nk max_size:32 -ZcashDisplayAddress.rivk max_size:32 +ZcashDisplayAddress.expected_seed_fingerprint max_size:32 ZcashAddress.address max_size:256 +ZcashAddress.seed_fingerprint max_size:32 diff --git a/messages-zcash.proto b/messages-zcash.proto index e6e14445..f03848b7 100644 --- a/messages-zcash.proto +++ b/messages-zcash.proto @@ -11,13 +11,20 @@ syntax = "proto2"; option java_package = "com.keepkey.deviceprotocol"; option java_outer_classname = "KeepKeyMessageZcash"; +enum ZcashShieldedPool { + ZCASH_SHIELDED_POOL_ORCHARD = 0; + ZCASH_SHIELDED_POOL_IRONWOOD = 1; +} + /** * Request: Sign a Zcash shielded transaction (PCZT format) * * The PCZT contains pre-constructed transaction data with proofs. - * The device derives spend authorization keys, computes the sighash, - * and returns RedPallas signatures for each Orchard action. + * The device derives spend authorization keys, computes the sighash, validates + * every Orchard action, and returns compact RedPallas signatures only for + * actions explicitly marked is_spend=true. * + * @next ZcashTransparentAck * @next ZcashPCZTActionAck * @next Failure */ @@ -25,21 +32,38 @@ message ZcashSignPCZT { repeated uint32 address_n = 1; // ZIP-32 derivation path [32', 133', account'] optional uint32 account = 2; // Account index (alternative to full path) optional bytes pczt_data = 3; // Serialized PCZT data (may be chunked) - optional uint32 n_actions = 4; // Number of Orchard actions to sign + optional uint32 n_actions = 4; // Number of Orchard actions to stream and validate optional uint64 total_amount = 5; // Total ZEC amount (zatoshis) for user confirmation optional uint64 fee = 6; // Transaction fee (zatoshis) optional uint32 branch_id = 7; // Consensus branch ID // Phase 2a: sub-digests for on-device sighash computation optional bytes header_digest = 8; // 32-byte pre-computed header digest optional bytes transparent_digest = 9; // 32-byte transparent digest (or empty) - optional bytes sapling_digest = 10; // 32-byte sapling digest (or empty) + optional bytes sapling_digest = 10; // Reserved for future Sapling support; currently rejected optional bytes orchard_digest = 11; // 32-byte orchard digest // Phase 2b: bundle metadata for orchard digest verification optional uint32 orchard_flags = 12; // Orchard bundle flags byte optional int64 orchard_value_balance = 13; // Orchard value balance (LE i64) optional bytes orchard_anchor = 14; // 32-byte orchard anchor + // Phase 4: plaintext header fields for on-device header digest verification + optional uint32 tx_version = 15; // Transaction version (without overwinter bit) + optional uint32 version_group_id = 16; // Version group ID + optional uint32 lock_time = 17; // Transaction lock time + optional uint32 expiry_height = 18; // Transaction expiry height + // NU6.3 / transaction-v6 Orchard-family pool selection. The existing + // orchard_* metadata fields describe the selected action bundle for wire + // compatibility; ironwood_digest is the fifth v6 transaction component. + optional ZcashShieldedPool shielded_pool = 19 [default = ZCASH_SHIELDED_POOL_ORCHARD]; + optional bytes ironwood_digest = 20; // 32-byte Ironwood component digest (v6) // Phase 3: transparent shielding support + optional uint32 n_transparent_outputs = 29; // 0 for shielded-only (default) optional uint32 n_transparent_inputs = 30; // 0 for shielded-only (default), >0 for hybrid shielding tx + // Seed identity binding (ZIP-32 §6.1) + optional bytes expected_seed_fingerprint = 31; // 32-byte ZIP-32 §6.1 seed fingerprint: + // BLAKE2b-256("Zcash_HD_Seed_FP", + // I2LEBSP_8(len(seed)) || seed) + // If present, device verifies match against its own + // seed fingerprint and rejects with Failure on mismatch. } /** @@ -56,7 +80,8 @@ message ZcashPCZTAction { optional bytes sighash = 3; // 32-byte transaction sighash (ZIP 244) - legacy mode optional bytes cv_net = 4; // 32-byte value commitment optional uint64 value = 5; // Action value in zatoshis (for display) - optional bool is_spend = 6; // True if this action spends a note + optional bool is_spend = 6; // REQUIRED by firmware 7.15: true only for a real spend; + // false for dummy spends/output-only actions // Phase 2b: action fields for incremental orchard digest verification optional bytes nullifier = 7; // 32-byte nullifier optional bytes cmx = 8; // 32-byte note commitment @@ -66,6 +91,11 @@ message ZcashPCZTAction { optional bytes enc_noncompact = 12; // Remaining encrypted note bytes optional bytes rk = 13; // 32-byte randomized verification key optional bytes out_ciphertext = 14; // 80-byte output ciphertext + // Phase 4: plaintext Orchard output metadata for trusted display. + // Firmware recomputes cmx from recipient/value/rseed and nullifier before + // displaying the receiver/value and before emitting any signature. + optional bytes recipient = 15; // 43-byte Orchard receiver: d || pk_d + optional bytes rseed = 16; // 32-byte output note rseed } /** @@ -84,7 +114,9 @@ message ZcashPCZTActionAck { * @prev ZcashPCZTAction */ message ZcashSignedPCZT { - repeated bytes signatures = 1; // 64-byte RedPallas signatures, one per action + repeated bytes signatures = 1; // Compact 64-byte RedPallas signatures: one per + // is_spend=true action, in ascending action-index order; + // an all-dummy shield transaction returns zero optional bytes txid = 2; // 32-byte computed transaction ID } @@ -116,64 +148,110 @@ message ZcashOrchardFVK { optional bytes ak = 1; // 32-byte authorizing key (Pallas point) optional bytes nk = 2; // 32-byte nullifier deriving key optional bytes rivk = 3; // 32-byte commitment randomness key + optional bytes seed_fingerprint = 4; // 32-byte ZIP-32 §6.1 seed fingerprint: + // BLAKE2b-256("Zcash_HD_Seed_FP", + // I2LEBSP_8(len(seed)) || seed) + // Stable identity of the device's seed; lets a host pin an FVK + // to a specific seed across sessions. +} + +/** + * Request: Transparent output data for hybrid transactions. + * Sent before transparent inputs so the device can review standard + * transparent recipients before any signature is emitted. + * + * @next ZcashTransparentAck + * @next ZcashPCZTActionAck + * @next Failure + */ +message ZcashTransparentOutput { + required uint32 index = 1; // Output index within the transaction + optional uint64 amount = 2; // Output value in zatoshis + optional bytes script_pubkey = 3; // Standard P2PKH/P2SH scriptPubKey } /** * Request: Transparent input data for hybrid shielding transactions. - * Sent one per transparent input during the transparent signing phase. - * The device ECDSA-signs the per-input sighash with the secp256k1 key - * at the provided BIP44 path. + * Sent after all transparent outputs have been streamed. * - * Flow: after ZcashSignPCZT with n_transparent_inputs > 0, the device - * responds with ZcashPCZTActionAck. For each transparent input, the host - * sends ZcashTransparentInput and receives ZcashTransparentSig. After - * all transparent inputs, the device transitions to the Orchard phase. + * The device stores every input first because ZIP-244 per-input transparent + * sighashes commit to all transparent prevouts, values, scripts, sequences, + * and outputs. Host-provided sighash is legacy and rejected when present. * - * @next ZcashTransparentSig + * @next ZcashTransparentAck + * @next ZcashTransparentSigned * @next Failure */ message ZcashTransparentInput { required uint32 index = 1; // Input index within the transaction - required bytes sighash = 2; // 32-byte per-input sighash (host-computed, ZIP-244) + optional bytes sighash = 2; // Legacy host-computed sighash; rejected when present repeated uint32 address_n = 3; // BIP44 path [44', 133', 0', 0, 0] - optional uint64 amount = 4; // Input value in zatoshis (for display verification) + optional uint64 amount = 4; // Input value in zatoshis + optional bytes prevout_txid = 5; // Previous transaction ID + optional uint32 prevout_index = 6; // Previous output index + optional uint32 sequence = 7; // Input sequence + optional bytes script_pubkey = 8; // Previous output scriptPubKey +} + +/** + * Response: Acknowledgment requesting the next transparent item. + * + * @prev ZcashSignPCZT + * @prev ZcashTransparentOutput + * @prev ZcashTransparentInput + */ +message ZcashTransparentAck { + optional uint32 next_output_index = 1; // Next transparent output index + optional uint32 next_input_index = 2; // Next transparent input index } /** - * Response: ECDSA signature for a transparent input. + * Response: ECDSA signatures for transparent inputs. * * @prev ZcashTransparentInput */ -message ZcashTransparentSig { - required bytes signature = 1; // DER ECDSA signature (72-73 bytes) - optional uint32 next_index = 2; // Next transparent input index, or 0xFF = done +message ZcashTransparentSigned { + repeated bytes signatures = 1; // DER ECDSA signatures, one per transparent input } /** - * Request: Display and verify a Zcash unified address on device. + * Request: Display the device-derived Orchard unified address on screen. + * + * The device derives the Orchard-only Unified Address (Sinsemilla + SWU + * hash-to-curve, default diversifier index 0) from its own seed at the + * requested account and shows it on the OLED with a QR code. What appears + * on screen is bound to this device — there is no host-supplied address + * to validate. + * + * Either account or a complete address_n path (m/32'/133'/account', all + * hardened) is REQUIRED. The device rejects requests that omit both. * - * The host provides the unified address string and the FVK components - * (ak, nk, rivk). The device re-derives its own Orchard keys from seed - * and compares them against the provided FVK to verify the Orchard - * receiver belongs to this device. + * Fields 3–6 (host-supplied address, ak, nk, rivk) were removed when the + * device gained on-device UA derivation: FVK-match attestation against a + * host-built UA is strictly weaker than device-derived display and was + * dropped. Field numbers are reserved to prevent reuse. * * @next ZcashAddress * @next Failure */ message ZcashDisplayAddress { - repeated uint32 address_n = 1; // ZIP-32 derivation path [32', 133', account'] - optional uint32 account = 2; // Account index (alternative to full path) - optional string address = 3; // Unified address string (u1...) - optional bytes ak = 4; // 32-byte authorizing key for verification - optional bytes nk = 5; // 32-byte nullifier deriving key for verification - optional bytes rivk = 6; // 32-byte commitment randomness key for verification + reserved 3, 4, 5, 6; + reserved "address", "ak", "nk", "rivk"; + repeated uint32 address_n = 1; // ZIP-32 path [32', 133', account'] — required if account omitted + optional uint32 account = 2; // Account index — required if address_n omitted + optional bytes expected_seed_fingerprint = 7; // 32-byte ZIP-32 §6.1 seed fingerprint. + // If present, device verifies match against its own + // seed fingerprint and rejects with Failure on mismatch. } /** - * Response: Verified Zcash address. + * Response: Confirmed Zcash address after user approval on device. * * @prev ZcashDisplayAddress */ message ZcashAddress { - optional string address = 1; // Verified unified address string + optional string address = 1; // Confirmed unified address + optional bytes seed_fingerprint = 2; // 32-byte ZIP-32 §6.1 seed fingerprint of the attesting + // device. Returned alongside the confirmed address so a host + // can record that this UA is bound to this device's seed. } diff --git a/messages.proto b/messages.proto index ca35898c..9357211c 100644 --- a/messages.proto +++ b/messages.proto @@ -100,6 +100,17 @@ enum MessageType { // Ethereum Clear Signing MessageType_EthereumTxMetadata = 115 [ (wire_in) = true ]; MessageType_EthereumMetadataAck = 116 [ (wire_out) = true ]; + MessageType_LoadClearsignSigner = 117 [ (wire_in) = true ]; + + // Structured EIP-712, device-driven field streaming. Allocated in a fresh + // block rather than after the 108-117 Ethereum run: the low range is where + // upstream Trezor allocates too, and keeping clear of it means adopting more + // of their messages later never collides. + MessageType_EthereumSignTypedData = 1704 [ (wire_in) = true ]; + MessageType_EthereumTypedDataStructRequest = 1705 [ (wire_out) = true ]; + MessageType_EthereumTypedDataStructAck = 1706 [ (wire_in) = true ]; + MessageType_EthereumTypedDataValueRequest = 1707 [ (wire_out) = true ]; + MessageType_EthereumTypedDataValueAck = 1708 [ (wire_in) = true ]; // BIP-85 MessageType_GetBip85Mnemonic = 120 [ (wire_in) = true ]; @@ -217,9 +228,11 @@ enum MessageType { MessageType_ZcashGetOrchardFVK = 1304 [ (wire_in) = true ]; MessageType_ZcashOrchardFVK = 1305 [ (wire_out) = true ]; MessageType_ZcashTransparentInput = 1306 [ (wire_in) = true ]; - MessageType_ZcashTransparentSig = 1307 [ (wire_out) = true ]; + MessageType_ZcashTransparentSigned = 1307 [ (wire_out) = true ]; MessageType_ZcashDisplayAddress = 1308 [ (wire_in) = true ]; MessageType_ZcashAddress = 1309 [ (wire_out) = true ]; + MessageType_ZcashTransparentOutput = 1310 [ (wire_in) = true ]; + MessageType_ZcashTransparentAck = 1311 [ (wire_out) = true ]; // TRON MessageType_TronGetAddress = 1400 [ (wire_in) = true ]; @@ -239,6 +252,34 @@ enum MessageType { MessageType_TonSignedTx = 1503 [ (wire_out) = true ]; MessageType_TonSignMessage = 1504 [ (wire_in) = true ]; MessageType_TonMessageSignature = 1505 [ (wire_out) = true ]; + + // Hive + MessageType_HiveGetPublicKey = 1600 [ (wire_in) = true ]; + MessageType_HivePublicKey = 1601 [ (wire_out) = true ]; + MessageType_HiveSignTx = 1602 [ (wire_in) = true ]; + MessageType_HiveSignedTx = 1603 [ (wire_out) = true ]; + MessageType_HiveGetPublicKeys = 1604 [ (wire_in) = true ]; + MessageType_HivePublicKeys = 1605 [ (wire_out) = true ]; + MessageType_HiveSignAccountCreate = 1606 [ (wire_in) = true ]; + MessageType_HiveSignedAccountCreate = 1607 [ (wire_out) = true ]; + MessageType_HiveSignAccountUpdate = 1608 [ (wire_in) = true ]; + MessageType_HiveSignedAccountUpdate = 1609 [ (wire_out) = true ]; + + // NEAR + MessageType_NearGetAddress = 1610 [ (wire_in) = true ]; + MessageType_NearAddress = 1611 [ (wire_out) = true ]; + MessageType_NearSignTx = 1612 [ (wire_in) = true ]; + MessageType_NearSignedTx = 1613 [ (wire_out) = true ]; + MessageType_HiveSignMessage = 1614 [ (wire_in) = true ]; + MessageType_HiveSignedMessage = 1615 [ (wire_out) = true ]; + MessageType_HiveSignOperations = 1616 [ (wire_in) = true ]; + MessageType_HiveSignedOperations = 1617 [ (wire_out) = true ]; + + // Advanced-mode ClearSign studio / schema attestation + MessageType_ClearsignAttestorGetPublicKey = 1700 [ (wire_in) = true ]; + MessageType_ClearsignAttestorPublicKey = 1701 [ (wire_out) = true ]; + MessageType_ClearsignAttestorSign = 1702 [ (wire_in) = true ]; + MessageType_ClearsignAttestorSignature = 1703 [ (wire_out) = true ]; } //////////////////// @@ -293,6 +334,11 @@ message Features { optional bool wipe_code_protection = 25; optional uint32 auto_lock_delay_ms = 26; // Current auto lock delay (in milliseconds) + optional bool supports_taproot = + 27; // Firmware can derive and spend P2TR (BIP-86 / BIP-340 / BIP-341). + // Lets a host detect taproot support directly instead of inferring + // it from a firmware version, which breaks whenever the feature is + // retargeted to a different release. } /** @@ -545,6 +591,9 @@ message ResetDevice { 7; // Initialize without ever showing the recovery sentence. optional uint32 auto_lock_delay_ms = 8; // Screensaver Timeout optional uint32 u2f_counter = 9; // U2F Counter + optional bool dice_entropy = + 10; // collect dice rolls on the device and mix them into the internal + // entropy before it is displayed or committed } /** @@ -955,6 +1004,10 @@ message FirmwareUpload { */ message DebugLinkDecision { required bool yes_no = 1; // true for "Confirm", false for "Cancel" + optional string input = + 2; // synthetic keyboard input for on-device entry flows (e.g. dice + // rolls '1'-'6', 'u' for undo); kept short so the decoded struct + // fits the tiny-message buffer } /** @@ -989,6 +1042,9 @@ message DebugLinkState { 12; // last auto completed recovery word optional bytes firmware_hash = 13; // hash of the application and meta header optional bytes storage_hash = 14; // hash of storage + optional bytes dice_digest = + 15; // SHA-256 of the ASCII dice-roll string collected during a + // dice_entropy ResetDevice workflow } /** @@ -1020,3 +1076,47 @@ message DebugLinkFillConfig {} message ChangeWipeCode { optional bool remove = 1; // is wipe code removal requested? } + +////////////////////////// +// Clearsign attestor // +////////////////////////// + +/** + * Request: derive and return the clearsign attestation public key. + * The attestation key is derived from the seed at a dedicated hardened path + * and is unrelated to any coin key. Available in regular firmware only while + * AdvancedMode is enabled. + * @next ClearsignAttestorPublicKey + * @next Failure + */ +message ClearsignAttestorGetPublicKey {} + +/** + * Response: compressed attestation public key + * @prev ClearsignAttestorGetPublicKey + */ +message ClearsignAttestorPublicKey { + optional bytes public_key = 1; // 33-byte compressed secp256k1 +} + +/** + * Request: validate a clearsign descriptor payload and attest it. + * The device parses the payload with the SAME validator verifying devices + * run (currently KKSOLSC1 reusable Solana instruction schemas) and refuses + * anything malformed — this message can never sign arbitrary bytes. + * Requires an unlocked session and an on-device confirmation. + * @next ClearsignAttestorSignature + * @next Failure + */ +message ClearsignAttestorSign { + optional bytes payload = 1; // canonical descriptor payload (magic-prefixed) +} + +/** + * Response: attestation over the validated payload + * @prev ClearsignAttestorSign + */ +message ClearsignAttestorSignature { + optional bytes signature = 1; // 64-byte compact secp256k1 ECDSA over SHA256(payload) + optional bytes public_key = 2; // 33-byte compressed attestation pubkey +} diff --git a/package-lock.json b/package-lock.json index 462ec2a5..60628403 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,140 +1,349 @@ { "name": "@keepkey/device-protocol", "version": "7.14.1", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@protobufjs/aspromise": { + "packages": { + "": { + "name": "@keepkey/device-protocol", + "version": "7.14.1", + "license": "ISC", + "dependencies": { + "google-protobuf": "3.21.4", + "pbjs": "^0.0.5" + }, + "devDependencies": { + "grpc-tools": "1.13.1", + "protobufjs": "^6.8.8", + "ts-protoc-gen": "^0.10.0" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz", + "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==", + "dev": true, + "dependencies": { + "consola": "^3.2.3", + "detect-libc": "^2.0.0", + "https-proxy-agent": "^7.0.5", + "node-fetch": "^2.6.7", + "nopt": "^8.0.0", + "semver": "^7.5.3", + "tar": "^7.4.0" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", "dev": true }, - "@protobufjs/base64": { + "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "dev": true }, - "@protobufjs/codegen": { + "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", "dev": true }, - "@protobufjs/eventemitter": { + "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", "dev": true }, - "@protobufjs/fetch": { + "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "dev": true, - "requires": { + "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, - "@protobufjs/float": { + "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", "dev": true }, - "@protobufjs/inquire": { + "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", "dev": true }, - "@protobufjs/path": { + "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", "dev": true }, - "@protobufjs/pool": { + "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", "dev": true }, - "@protobufjs/utf8": { + "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", "dev": true }, - "@types/long": { + "node_modules/@types/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==", "dev": true }, - "@types/node": { + "node_modules/@types/node": { "version": "10.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.6.tgz", "integrity": "sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg==", "dev": true }, - "bytebuffer": { + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/bytebuffer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", - "requires": { + "dependencies": { "long": "~3" }, - "dependencies": { - "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" - } + "engines": { + "node": ">=0.8" + } + }, + "node_modules/bytebuffer/node_modules/long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", + "engines": { + "node": ">=0.6" } }, - "commander": { + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "requires": { + "dependencies": { "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" } }, - "google-protobuf": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.7.1.tgz", - "integrity": "sha512-6fvlUey6cNKtWSEn1bt4CT4wc2EID1fVluHS1dOnqIlxyIu3cBid2BvWE8Rwl6wN+hRTgiAKhfyydAGV/weZYQ==" + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "graceful-readlink": { + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/google-protobuf": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz", + "integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==" + }, + "node_modules/graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" }, - "long": { + "node_modules/grpc-tools": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.13.1.tgz", + "integrity": "sha512-0sttMUxThNIkCTJq5qI0xXMz5zWqV2u3yG1kR3Sj9OokGIoyRBFjoInK9NyW7x5fH7knj48Roh1gq5xbl0VoDQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^2.0.0" + }, + "bin": { + "grpc_tools_node_protoc": "bin/protoc.js", + "grpc_tools_node_protoc_plugin": "bin/protoc_plugin.js" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", "dev": true }, - "pbjs": { + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dev": true, + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/pbjs": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/pbjs/-/pbjs-0.0.5.tgz", "integrity": "sha1-tMiOFarEVSygkiqmTNUzjv00R78=", - "requires": { + "dependencies": { "bytebuffer": "5.0.1", "commander": "2.9.0", "protocol-buffers-schema": "3.1.0" + }, + "bin": { + "pbjs": "cli.js" } }, - "protobufjs": { + "node_modules/protobufjs": { "version": "6.8.8", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", "dev": true, - "requires": { + "hasInstallScript": true, + "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", @@ -148,18 +357,87 @@ "@types/long": "^4.0.0", "@types/node": "^10.1.0", "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" } }, - "protocol-buffers-schema": { + "node_modules/protocol-buffers-schema": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.1.0.tgz", "integrity": "sha1-2KgZVJ6tPmvRievp5Q6WY2u8XMc=" }, - "ts-protoc-gen": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/ts-protoc-gen/-/ts-protoc-gen-0.9.0.tgz", - "integrity": "sha512-cFEUTY9U9o6C4DPPfMHk2ZUdIAKL91hZN1fyx5Stz3g56BDVOC7hk+r5fEMCAGaaIgi2akkT1a2hrxu1wo2Phg==", + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/ts-protoc-gen": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/ts-protoc-gen/-/ts-protoc-gen-0.10.0.tgz", + "integrity": "sha512-EEbgDWNHK3CvcNhmib94I4HMO23qLddjLRdXW8EUE11VJxbi3n5J0l2DiX/L1pijOaPTkbEoRK+zQinKgKGqsw==", + "dev": true, + "dependencies": { + "google-protobuf": "^3.6.1" + }, + "bin": { + "protoc-gen-ts": "bin/protoc-gen-ts" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "engines": { + "node": ">=18" + } } } } diff --git a/package.json b/package.json index 51f6d535..614daf16 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,10 @@ "scripts": { "clean": "rm -rf ./lib/*.js ./lib/*.ts", "build": "npm run build:js && npm run build:json && npm run build:postprocess", - "build:js": "protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:./lib --ts_out=./lib types.proto messages.proto messages-ethereum.proto messages-eos.proto messages-nano.proto messages-cosmos.proto messages-binance.proto messages-ripple.proto messages-tendermint.proto messages-thorchain.proto messages-osmosis.proto messages-mayachain.proto messages-solana.proto messages-tron.proto messages-ton.proto messages-zcash.proto", - "build:json": "pbjs --keep-case -t json ./types.proto ./messages.proto ./messages-ethereum.proto ./messages-eos.proto ./messages-nano.proto ./messages-cosmos.proto ./messages-binance.proto ./messages-ripple.proto ./messages-tendermint.proto ./messages-thorchain.proto ./messages-osmosis.proto ./messages-mayachain.proto ./messages-solana.proto ./messages-tron.proto ./messages-ton.proto ./messages-zcash.proto > ./lib/proto.json", + "build:js": "mkdir -p ./lib && ./node_modules/.bin/grpc_tools_node_protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:./lib --ts_out=./lib types.proto messages.proto messages-ethereum.proto messages-eos.proto messages-nano.proto messages-cosmos.proto messages-binance.proto messages-ripple.proto messages-tendermint.proto messages-thorchain.proto messages-osmosis.proto messages-mayachain.proto messages-solana.proto messages-tron.proto messages-ton.proto messages-zcash.proto messages-hive.proto messages-near.proto", + "build:json": "pbjs --keep-case -t json ./types.proto ./messages.proto ./messages-ethereum.proto ./messages-eos.proto ./messages-nano.proto ./messages-cosmos.proto ./messages-binance.proto ./messages-ripple.proto ./messages-tendermint.proto ./messages-thorchain.proto ./messages-osmosis.proto ./messages-mayachain.proto ./messages-solana.proto ./messages-tron.proto ./messages-ton.proto ./messages-zcash.proto ./messages-hive.proto ./messages-near.proto > ./lib/proto.json", "build:postprocess": "find ./lib -name \"*.js\" -exec sed -i '' -e \"s/var global = Function(\\'return this\\')();/var global = (function(){ return this }).call(null);/g\" {} \\;", + "prepare": "npm run build:js", "prepublishOnly": "npm run build", "test": "echo \"Error: no test specified\" && exit 1" }, @@ -21,11 +22,12 @@ "author": "", "license": "ISC", "devDependencies": { + "grpc-tools": "1.13.1", "protobufjs": "^6.8.8", "ts-protoc-gen": "^0.10.0" }, "dependencies": { - "google-protobuf": "^3.7.0-rc.2", + "google-protobuf": "3.21.4", "pbjs": "^0.0.5" } } diff --git a/tools/check_zcash_contract.py b/tools/check_zcash_contract.py new file mode 100644 index 00000000..bc64d57c --- /dev/null +++ b/tools/check_zcash_contract.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Pin the RC18 Zcash wire identifiers and compact-signature contract.""" + +import re +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +ZCASH = (ROOT / "messages-zcash.proto").read_text() +MESSAGES = (ROOT / "messages.proto").read_text() + + +def message_body(name): + match = re.search(r"message\s+%s\s*\{(.*?)\n\}" % name, ZCASH, re.S) + if not match: + raise AssertionError("missing message %s" % name) + return match.group(1) + + +def require_field(message, declaration): + body = message_body(message) + if not re.search(r"^\s*%s\s*(?://.*)?$" % declaration, body, re.M): + raise AssertionError("%s is missing field contract: %s" % (message, declaration)) + + +FIELDS = [ + ("ZcashSignPCZT", r"optional uint32 n_actions = 4;"), + ("ZcashSignPCZT", r"optional uint32 n_transparent_outputs = 29;"), + ("ZcashSignPCZT", r"optional uint32 n_transparent_inputs = 30;"), + ("ZcashSignPCZT", r"optional bytes expected_seed_fingerprint = 31;"), + ("ZcashPCZTAction", r"optional bool is_spend = 6;"), + ("ZcashPCZTAction", r"optional bytes recipient = 15;"), + ("ZcashPCZTAction", r"optional bytes rseed = 16;"), + ("ZcashSignedPCZT", r"repeated bytes signatures = 1;"), + ("ZcashTransparentOutput", r"required uint32 index = 1;"), + ("ZcashTransparentInput", r"required uint32 index = 1;"), +] + +for field in FIELDS: + require_field(*field) + + +MESSAGE_IDS = { + "ZcashSignPCZT": (1300, "wire_in"), + "ZcashPCZTAction": (1301, "wire_in"), + "ZcashPCZTActionAck": (1302, "wire_out"), + "ZcashSignedPCZT": (1303, "wire_out"), + "ZcashGetOrchardFVK": (1304, "wire_in"), + "ZcashOrchardFVK": (1305, "wire_out"), + "ZcashTransparentInput": (1306, "wire_in"), + "ZcashTransparentSigned": (1307, "wire_out"), + "ZcashDisplayAddress": (1308, "wire_in"), + "ZcashAddress": (1309, "wire_out"), + "ZcashTransparentOutput": (1310, "wire_in"), + "ZcashTransparentAck": (1311, "wire_out"), +} + +for name, (number, direction) in MESSAGE_IDS.items(): + pattern = ( + r"MessageType_%s\s*=\s*%d\s*\[\s*\(%s\)\s*=\s*true\s*\]\s*;" + % (name, number, direction) + ) + if not re.search(pattern, MESSAGES): + raise AssertionError("wrong message ID or wire direction for %s" % name) + + +if not re.search(r"one per\s*// is_spend=true action", ZCASH): + raise AssertionError("ZcashSignedPCZT must document compact real-spend signatures") + +print("RC18 Zcash protocol contract: ok") diff --git a/types.proto b/types.proto index 18cf8fab..9ceaf72c 100644 --- a/types.proto +++ b/types.proto @@ -134,6 +134,7 @@ enum ButtonRequestType { ButtonRequest_RemoveWipeCode = 36; ButtonRequest_ChangeWipeCode = 37; ButtonRequest_CreateWipeCode = 38; + ButtonRequest_DiceRoll = 39; } /** diff --git a/yarn.lock b/yarn.lock index c4f17406..ce3c2145 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,92 +2,205 @@ # yarn lockfile v1 +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + +"@mapbox/node-pre-gyp@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz" + integrity sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg== + dependencies: + consola "^3.2.3" + detect-libc "^2.0.0" + https-proxy-agent "^7.0.5" + node-fetch "^2.6.7" + nopt "^8.0.0" + semver "^7.5.3" + tar "^7.4.0" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= "@protobufjs/base64@^1.1.2": version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== "@protobufjs/codegen@^2.0.4": version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== "@protobufjs/eventemitter@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= "@protobufjs/fetch@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= dependencies: "@protobufjs/aspromise" "^1.1.1" "@protobufjs/inquire" "^1.1.0" "@protobufjs/float@^1.0.2": version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= "@protobufjs/inquire@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= "@protobufjs/path@^1.1.2": version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= "@protobufjs/pool@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= "@protobufjs/utf8@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= "@types/long@^4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" + resolved "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz" + integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q== "@types/node@^10.1.0": - version "10.12.24" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.24.tgz#b13564af612a22a20b5d95ca40f1bffb3af315cf" + version "10.14.6" + resolved "https://registry.npmjs.org/@types/node/-/node-10.14.6.tgz" + integrity sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg== + +abbrev@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz" + integrity sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg== + +agent-base@^7.1.2: + version "7.1.4" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz" + integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== bytebuffer@5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd" + resolved "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz" + integrity sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0= dependencies: long "~3" +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + commander@2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" + integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= dependencies: graceful-readlink ">= 1.0.0" -google-protobuf@^3.6.1: - version "3.9.0" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.9.0.tgz#1f33e51e7993ea51e758a82650ad4347273b9bc6" +consola@^3.2.3: + version "3.4.2" + resolved "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz" + integrity sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA== + +debug@4: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +detect-libc@^2.0.0: + version "2.1.2" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== -google-protobuf@^3.7.0-rc.2: - version "3.7.0-rc.2" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.7.0-rc.2.tgz#a65e9216825065099c4ff243eee9e16e764cc2c9" +google-protobuf@^3.6.1, google-protobuf@3.21.4: + version "3.21.4" + resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz" + integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ== "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + +grpc-tools@1.13.1: + version "1.13.1" + resolved "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.13.1.tgz" + integrity sha512-0sttMUxThNIkCTJq5qI0xXMz5zWqV2u3yG1kR3Sj9OokGIoyRBFjoInK9NyW7x5fH7knj48Roh1gq5xbl0VoDQ== + dependencies: + "@mapbox/node-pre-gyp" "^2.0.0" + +https-proxy-agent@^7.0.5: + version "7.0.6" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" long@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== long@~3: version "3.2.0" - resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" + resolved "https://registry.npmjs.org/long/-/long-3.2.0.tgz" + integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= + +minipass@^7.0.4, minipass@^7.1.2: + version "7.1.3" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz" + integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== + +minizlib@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz" + integrity sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw== + dependencies: + minipass "^7.1.2" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +nopt@^8.0.0: + version "8.1.0" + resolved "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz" + integrity sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A== + dependencies: + abbrev "^3.0.0" pbjs@^0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/pbjs/-/pbjs-0.0.5.tgz#b4c88e15aac4552ca0922aa64cd5338efd3447bf" + resolved "https://registry.npmjs.org/pbjs/-/pbjs-0.0.5.tgz" + integrity sha1-tMiOFarEVSygkiqmTNUzjv00R78= dependencies: bytebuffer "5.0.1" commander "2.9.0" @@ -95,7 +208,8 @@ pbjs@^0.0.5: protobufjs@^6.8.8: version "6.8.8" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz" + integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -113,10 +227,51 @@ protobufjs@^6.8.8: protocol-buffers-schema@3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.1.0.tgz#d8a819549ead3e6bd189ebe9e50e96636bbc5cc7" + resolved "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.1.0.tgz" + integrity sha1-2KgZVJ6tPmvRievp5Q6WY2u8XMc= + +semver@^7.5.3: + version "7.8.5" + resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz" + integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA== + +tar@^7.4.0: + version "7.5.22" + resolved "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz" + integrity sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.1.0" + yallist "^5.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-protoc-gen@^0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/ts-protoc-gen/-/ts-protoc-gen-0.10.0.tgz#f708d99be59ad0be6bdce6f4fe893ec41757d2c9" + resolved "https://registry.npmjs.org/ts-protoc-gen/-/ts-protoc-gen-0.10.0.tgz" + integrity sha512-EEbgDWNHK3CvcNhmib94I4HMO23qLddjLRdXW8EUE11VJxbi3n5J0l2DiX/L1pijOaPTkbEoRK+zQinKgKGqsw== dependencies: google-protobuf "^3.6.1" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==