diff --git a/core/src/apps/bitcoin/sign_taproot.py b/core/src/apps/bitcoin/sign_taproot.py index 143f6a644..cce503cfa 100644 --- a/core/src/apps/bitcoin/sign_taproot.py +++ b/core/src/apps/bitcoin/sign_taproot.py @@ -2,15 +2,16 @@ from trezor import wire from trezor.crypto import base58 -from trezor.enums import AmountUnit, OutputScriptType +from trezor.enums import AmountUnit, InputScriptType, OutputScriptType from trezor.lvglui.scrs import lv from trezor.messages import SignedPsbt, SignTx, TxInput, TxOutput from apps.common import address_type from apps.ur_registry.chains.bitcoin.psbt.psbt import PSBT -from apps.ur_registry.chains.bitcoin.psbt.script import is_witness +from apps.ur_registry.chains.bitcoin.psbt.script import is_witness, parse_op_return_data from apps.ur_registry.chains.bitcoin.psbt.serialize import ser_string +from . import addresses, scripts from .common import ( SigHashType, bip340_sign, @@ -25,15 +26,29 @@ # from .sign_tx import tx_weight if TYPE_CHECKING: + from trezor.crypto import bip32 from apps.common.coininfo import CoinInfo from apps.common.keychain import Keychain from trezor.messages import SignPsbt +def _validate_change_output_script( + script_type: InputScriptType, + node: "bip32.HDNode", + script_pubkey: bytes, + coin: "CoinInfo", +) -> None: + address = addresses.get_address(script_type, coin, node) + if scripts.output_derive_script(address, coin) != script_pubkey: + raise wire.DataError("Invalid change output script") + + @with_keychain async def sign_taproot( ctx: wire.Context, msg: SignPsbt, keychain: Keychain, coin: CoinInfo ) -> SignedPsbt: + if not coin.taproot: + raise wire.DataError("Taproot is not enabled on this coin") if not msg.psbt: raise wire.DataError("Missing psbt") try: @@ -55,7 +70,7 @@ async def sign_taproot( found_ours = False contains_script_path_spending = False for i, input in enumerate(psbt.inputs): - if input.prev_txid is None: + if not input.prev_txid: raise wire.DataError("Missing previous transaction ID") if input.prev_out is None: raise wire.DataError("Missing previous output index") @@ -138,10 +153,24 @@ async def sign_taproot( if out.nValue != 0: if not (contains_script_path_spending and len(psbt.inputs) == 1): raise wire.DataError("OpReturn output should have 0 value") - op_return_data = out.scriptPubKey[2:] + op_return_data = parse_op_return_data(out.scriptPubKey) + if op_return_data is None or len(op_return_data) > 80: + raise wire.DataError("Invalid PSBT, unsupported OP_RETURN") else: raise Exception("Invalid output type") + if len(output.hd_keypaths) + len(output.tap_bip32_paths) > 1: + raise wire.DataError("Multiple derivation paths are not allowed") + + change_key_origin = None + change_script_type = None + if out.is_p2pkh(): + change_script_type = InputScriptType.SPENDADDRESS + elif out.is_p2sh(): + change_script_type = InputScriptType.SPENDP2SHWITNESS + elif wit and ver == 0: + change_script_type = InputScriptType.SPENDWITNESS + if not wit or (wit and ver == 0): for _, keypath in output.hd_keypaths.items(): if keypath.fingerprint != master_fp: @@ -153,9 +182,10 @@ async def sign_taproot( raise wire.DataError( "Master fingerprint does not match master key" ) - change_out += out.nValue - is_change_out = True + if change_script_type is not None: + change_key_origin = keypath elif wit and ver == 1: + change_script_type = InputScriptType.SPENDTAPROOT for key, (_, origin) in output.tap_bip32_paths.items(): if not ( key == output.tap_internal_key and origin.fingerprint == master_fp @@ -163,8 +193,18 @@ async def sign_taproot( raise wire.DataError( "Invalid parameters, only key path change is allowed" ) - change_out += out.nValue - is_change_out = True + change_key_origin = origin + + if change_key_origin is not None and change_script_type is not None: + node = keychain.derive(change_key_origin.path) + _validate_change_output_script( + change_script_type, + node, + out.scriptPubKey, + coin, + ) + change_out += out.nValue + is_change_out = True sig_hasher.add_output( txo=TxOutput( amount=out.nValue, @@ -179,7 +219,7 @@ async def sign_taproot( "op_return_data": op_return_data, "script_type": OutputScriptType.PAYTOOPRETURN, } - if op_return_data + if op_return_data is not None else {} ) await layout.confirm_output( @@ -188,7 +228,7 @@ async def sign_taproot( coin, AmountUnit.BITCOIN, ) - if total_in <= total_out: + if total_in < total_out: raise wire.DataError("Insufficient funds") tx_locktime = psbt.compute_lock_time() diff --git a/core/src/apps/bitcoin/sign_tx/layout.py b/core/src/apps/bitcoin/sign_tx/layout.py index e2e859b78..4caf3225b 100644 --- a/core/src/apps/bitcoin/sign_tx/layout.py +++ b/core/src/apps/bitcoin/sign_tx/layout.py @@ -51,6 +51,8 @@ async def confirm_output( if data is None: raise wire.DataError("Missing OP_RETURN data") if omni.is_valid(data): + if output.amount != 0: + raise wire.DataError("OMNI output should have 0 value") # OMNI transaction layout = layouts.confirm_metadata( ctx, diff --git a/core/src/apps/ur_registry/chains/bitcoin/psbt/psbt.py b/core/src/apps/ur_registry/chains/bitcoin/psbt/psbt.py index 5e961aeb6..f5f1e7adf 100644 --- a/core/src/apps/ur_registry/chains/bitcoin/psbt/psbt.py +++ b/core/src/apps/ur_registry/chains/bitcoin/psbt/psbt.py @@ -1200,7 +1200,7 @@ def get_unsigned_tx(self) -> CTransaction: tx = CTransaction() tx.nVersion = self.tx_version - self.nLockTime = self.compute_lock_time() + tx.nLockTime = self.compute_lock_time() for psbt_in in self.inputs: if psbt_in.prev_txid is None: diff --git a/core/src/apps/ur_registry/chains/bitcoin/psbt/script.py b/core/src/apps/ur_registry/chains/bitcoin/psbt/script.py index cfbd0bc61..5153c7542 100644 --- a/core/src/apps/ur_registry/chains/bitcoin/psbt/script.py +++ b/core/src/apps/ur_registry/chains/bitcoin/psbt/script.py @@ -13,7 +13,30 @@ def is_opreturn(script: bytes) -> bool: :param script: The script :returns: Whether the script is an OP_RETURN output script """ - return script[0] == 0x6A + return len(script) > 2 and script[0] == 0x6A + + +def parse_op_return_data(script: bytes) -> bytes | None: + """Return the OP_RETURN payload if it uses a supported encoding.""" + if not is_opreturn(script): + return None + + push_opcode = script[1] + if push_opcode < 0x4C: + payload_offset = 2 + payload_length = push_opcode + elif push_opcode == 0x4C: + payload_offset = 3 + payload_length = script[2] + if payload_length < 0x4C: + return None + else: + return None + + if len(script) != payload_offset + payload_length: + return None + + return script[payload_offset:] def is_p2sh(script: bytes) -> bool: diff --git a/core/src/trezor/lvglui/i18n/keys.py b/core/src/trezor/lvglui/i18n/keys.py index 8aedccb04..0dff561b6 100644 --- a/core/src/trezor/lvglui/i18n/keys.py +++ b/core/src/trezor/lvglui/i18n/keys.py @@ -1823,7 +1823,8 @@ VERIFY_DEVICE_CONNECT_DEVICE_DESC = 826 # Verify Device TITLE__VEIRIFY_DEVICE = 827 -# Visit https://bit.ly/3ZsHB40 for additional verification methods +# Visit https://help.onekey.so/en/articles/11461153 for additional verificatio +# n methods VERIFY_DEVICE_HELP_CENTER_TEXT = 828 # More Networks BUTTON__MORE_NETWORKS = 829 diff --git a/core/src/trezor/lvglui/i18n/locales/de.py b/core/src/trezor/lvglui/i18n/locales/de.py index 5ceb9d370..03b188536 100644 --- a/core/src/trezor/lvglui/i18n/locales/de.py +++ b/core/src/trezor/lvglui/i18n/locales/de.py @@ -828,7 +828,7 @@ "Gerät verbinden", "Öffnen Sie die OneKey App und verbinden Sie Ihr Gerät, um eine Wallet zu erstellen. Die Geräteüberprüfung wird automatisch durchgeführt.", "Gerät verifizieren", - "Besuchen Sie https://bit.ly/3ZsHB40 für zusätzliche Verifizierungsmethoden", + "Besuchen Sie https://help.onekey.so/en/articles/11461153 für zusätzliche Verifizierungsmethoden", "Weitere Netzwerke", "Weniger zeigen", "Bootloader-URL erfordert Geräteverifizierung in der OneKey App 5.5.0+", diff --git a/core/src/trezor/lvglui/i18n/locales/en.py b/core/src/trezor/lvglui/i18n/locales/en.py index e56dc8d62..7e86a288e 100644 --- a/core/src/trezor/lvglui/i18n/locales/en.py +++ b/core/src/trezor/lvglui/i18n/locales/en.py @@ -828,7 +828,7 @@ "Connect Device", "Open OneKey App and connect your device to create a wallet. Device verification will be performed automatically", "Verify Device", - "Visit https://bit.ly/3ZsHB40 for additional verification methods", + "Visit https://help.onekey.so/en/articles/11461153 for additional verification methods", "More Networks", "Show Less", "Bootloader URL requires device verification in OneKey App 5.5.0+", diff --git a/core/src/trezor/lvglui/i18n/locales/es.py b/core/src/trezor/lvglui/i18n/locales/es.py index b3f9d879b..f2c5ec04c 100644 --- a/core/src/trezor/lvglui/i18n/locales/es.py +++ b/core/src/trezor/lvglui/i18n/locales/es.py @@ -828,7 +828,7 @@ "Conectar dispositivo", "Abre la aplicación OneKey y conecta tu dispositivo para crear una billetera. La verificación del dispositivo se realizará automáticamente.", "Verificar dispositivo", - "Visita https://bit.ly/3ZsHB40 para métodos de verificación adicionales", + "Visita https://help.onekey.so/en/articles/11461153 para métodos de verificación adicionales", "Más redes", "Mostrar menos", "La URL del bootloader requiere verificación del dispositivo en la aplicación OneKey 5.5.0+", diff --git a/core/src/trezor/lvglui/i18n/locales/fr.py b/core/src/trezor/lvglui/i18n/locales/fr.py index 6b1d4a382..02af6e87d 100644 --- a/core/src/trezor/lvglui/i18n/locales/fr.py +++ b/core/src/trezor/lvglui/i18n/locales/fr.py @@ -828,7 +828,7 @@ "Connecter l'appareil", "Ouvrez l'application OneKey et connectez votre appareil pour créer un portefeuille. La vérification de l'appareil sera effectuée automatiquement.", "Vérifier l'appareil", - "Visitez https://bit.ly/3ZsHB40 pour des méthodes de vérification supplémentaires", + "Visitez https://help.onekey.so/en/articles/11461153 pour des méthodes de vérification supplémentaires", "Plus de réseaux", "Afficher moins", "L'URL du bootloader nécessite une vérification de l'appareil dans l'application OneKey 5.5.0+.", diff --git a/core/src/trezor/lvglui/i18n/locales/it.py b/core/src/trezor/lvglui/i18n/locales/it.py index cf48a52af..14f51ae8f 100644 --- a/core/src/trezor/lvglui/i18n/locales/it.py +++ b/core/src/trezor/lvglui/i18n/locales/it.py @@ -828,7 +828,7 @@ "Collega dispositivo", "Apri l'app OneKey e collega il tuo dispositivo per creare un portafoglio. La verifica del dispositivo verrà eseguita automaticamente", "Verifica dispositivo", - "Visita https://bit.ly/3ZsHB40 per metodi di verifica aggiuntivi", + "Visita https://help.onekey.so/en/articles/11461153 per metodi di verifica aggiuntivi", "Altre reti", "Mostra meno", "L'URL del bootloader richiede la verifica del dispositivo nell'app OneKey 5.5.0+", diff --git a/core/src/trezor/lvglui/i18n/locales/ja.py b/core/src/trezor/lvglui/i18n/locales/ja.py index eba8bb2bb..617c80643 100644 --- a/core/src/trezor/lvglui/i18n/locales/ja.py +++ b/core/src/trezor/lvglui/i18n/locales/ja.py @@ -828,7 +828,7 @@ "デバイスを接続する", "OneKey アプリを開いて、デバイスを接続してウォレットを作成します。デバイスの確認は自動的に行われます。", "デバイスを確認", - "追加の確認方法については、https://bit.ly/3ZsHB40 をご覧ください。", + "追加の確認方法については、https://help.onekey.so/en/articles/11461153 をご覧ください。", "その他のネットワーク", "表示を減らす", "ブートローダー URL は OneKey アプリ 5.5.0+ でデバイスの確認が必要です", diff --git a/core/src/trezor/lvglui/i18n/locales/ko.py b/core/src/trezor/lvglui/i18n/locales/ko.py index eff6d697b..e1ca4f8de 100644 --- a/core/src/trezor/lvglui/i18n/locales/ko.py +++ b/core/src/trezor/lvglui/i18n/locales/ko.py @@ -828,7 +828,7 @@ "기기 연결", "OneKey 앱을 열고 기기를 연결하여 지갑을 만드세요. 기기 검증은 자동으로 수행됩니다.", "기기 인증", - "추가 인증 방법은 https://bit.ly/3ZsHB40 를 방문하세요", + "추가 인증 방법은 https://help.onekey.so/en/articles/11461153 를 방문하세요", "더 많은 네트워크", "더 적게 표시", "부트로더 URL 은 OneKey App 5.5.0+ 에서 기기 인증이 필요합니다.", diff --git a/core/src/trezor/lvglui/i18n/locales/pt_br.py b/core/src/trezor/lvglui/i18n/locales/pt_br.py index af7a27457..4c8f27258 100644 --- a/core/src/trezor/lvglui/i18n/locales/pt_br.py +++ b/core/src/trezor/lvglui/i18n/locales/pt_br.py @@ -828,7 +828,7 @@ "Conectar Dispositivo", "Abra o aplicativo OneKey e conecte seu dispositivo para criar uma carteira. A verificação do dispositivo será realizada automaticamente", "Verificar Dispositivo", - "Visite https://bit.ly/3ZsHB40 para métodos adicionais de verificação", + "Visite https://help.onekey.so/en/articles/11461153 para métodos adicionais de verificação", "Mais Redes", "Mostrar menos", "A URL do Bootloader requer verificação do dispositivo no OneKey App 5.5.0+", diff --git a/core/src/trezor/lvglui/i18n/locales/ru.py b/core/src/trezor/lvglui/i18n/locales/ru.py index 17e39aec3..2a5017424 100644 --- a/core/src/trezor/lvglui/i18n/locales/ru.py +++ b/core/src/trezor/lvglui/i18n/locales/ru.py @@ -828,7 +828,7 @@ "Подключить устройство", "Откройте OneKey App и подключите ваше устройство, чтобы создать кошелек. Проверка устройства будет выполнена автоматически", "Проверка устройства", - "Посетите https://bit.ly/3ZsHB40 для получения дополнительных методов проверки", + "Посетите https://help.onekey.so/en/articles/11461153 для получения дополнительных методов проверки", "Больше сетей", "Показать меньше", "URL загрузчика требует проверки устройства в приложении OneKey версии 5.5.0 и выше", diff --git a/core/src/trezor/lvglui/i18n/locales/zh_cn.py b/core/src/trezor/lvglui/i18n/locales/zh_cn.py index c3af72d70..e507a7cf9 100644 --- a/core/src/trezor/lvglui/i18n/locales/zh_cn.py +++ b/core/src/trezor/lvglui/i18n/locales/zh_cn.py @@ -828,7 +828,7 @@ "连接设备", "打开 OneKey App 并连接您的设备以创建钱包。设备验证将自动进行", "验证设备", - "访问 https://bit.ly/3ZsHB40 获取更多验证方法", + "访问 https://help.onekey.so/en/articles/11461153 获取更多验证方法", "更多网络", "显示更少", "Bootloader URL 需要在 OneKey App 5.5.0+ 中进行设备验证", diff --git a/core/src/trezor/lvglui/i18n/locales/zh_hk.py b/core/src/trezor/lvglui/i18n/locales/zh_hk.py index e5364a1f5..ca288ed59 100644 --- a/core/src/trezor/lvglui/i18n/locales/zh_hk.py +++ b/core/src/trezor/lvglui/i18n/locales/zh_hk.py @@ -828,7 +828,7 @@ "連接裝置", "打開 OneKey App 並連接您的設備以創建錢包。設備驗證將自動進行", "驗證裝置", - "請訪問 https://bit.ly/3ZsHB40 以獲取其他驗證方法", + "請訪問 https://help.onekey.so/en/articles/11461153 以獲取其他驗證方法", "更多網絡", "顯示更少", "Bootloader URL 需要在 OneKey App 5.5.0+ 中進行設備驗證",