From 26aa4289b0e9cd57d958f5f4342aaa9c53851fc0 Mon Sep 17 00:00:00 2001 From: 10gic Date: Fri, 4 Oct 2024 16:14:48 +0800 Subject: [PATCH] [TON]: Support TON mintless jettons (#4041) * Support TON mintless jettons * Only adjust comments * Adjust TheOpenNetwork.proto --------- Co-authored-by: Sztergbaum Roman --- .../TestTheOpenNetworkSigner.kt | 8 +-- .../src/message/payload/jetton_transfer.rs | 7 ++- .../tw_ton/src/signing_request/builder.rs | 35 +++++------ .../src/signing_request/cell_creator.rs | 40 ++++++------ rust/chains/tw_ton/src/signing_request/mod.rs | 14 ++--- rust/tw_tests/tests/chains/ton/ton_sign.rs | 15 +++-- .../tests/chains/ton/ton_sign_wallet_v5r1.rs | 62 ++++++++++++++++--- src/proto/TheOpenNetwork.proto | 21 +++---- .../Blockchains/TheOpenNetworkTests.swift | 8 +-- 9 files changed, 123 insertions(+), 87 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt index 59b3fcdd465..69dd91abada 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt @@ -97,18 +97,14 @@ class TestTheOpenNetworkSigner { // "This transaction deploys Doge Chatbot contract" val commentPayload = "te6cckEBAQEANAAAZAAAAABUaGlzIHRyYW5zYWN0aW9uIGRlcGxveXMgRG9nZSBDaGF0Ym90IGNvbnRyYWN0v84vSg==" - val customPayload = TheOpenNetwork.CustomPayload.newBuilder() - .setStateInit(dogeChatbotStateInit) - .setPayload(commentPayload) - .build() - val transfer = TheOpenNetwork.Transfer.newBuilder() .setDest(dogeChatbotDeployingAddress) // 0.069 TON .setAmount(69_000_000) .setMode(TheOpenNetwork.SendMode.PAY_FEES_SEPARATELY_VALUE or TheOpenNetwork.SendMode.IGNORE_ACTION_PHASE_ERRORS_VALUE) .setBounceable(false) - .setCustomPayload(customPayload) + .setStateInit(dogeChatbotStateInit) + .setCustomPayload(commentPayload) val input = TheOpenNetwork.SigningInput.newBuilder() .setPrivateKey(ByteString.copyFrom(privateKey.data())) diff --git a/rust/chains/tw_ton/src/message/payload/jetton_transfer.rs b/rust/chains/tw_ton/src/message/payload/jetton_transfer.rs index b6e687551ae..82b552c6b2b 100644 --- a/rust/chains/tw_ton/src/message/payload/jetton_transfer.rs +++ b/rust/chains/tw_ton/src/message/payload/jetton_transfer.rs @@ -23,8 +23,6 @@ pub struct JettonTransferPayload { /// Address where to send a response with confirmation of a successful transfer and the rest of the incoming message Toncoins. response_destination: TonAddress, /// Optional custom data (which is used by either sender or receiver jetton wallet for inner logic). - /// At WalletCore, we do not use `custom_payload` at the moment. - #[allow(dead_code)] custom_payload: Option, /// Amount of nanotons to be sent to the destination address. forward_ton_amount: U256, @@ -65,6 +63,11 @@ impl JettonTransferPayload { self } + pub fn with_custom_payload(&mut self, custom_payload: Option) -> &mut Self { + self.custom_payload = custom_payload; + self + } + pub fn with_forward_ton_amount(&mut self, forward_ton_amount: U256) -> &mut Self { self.forward_ton_amount = forward_ton_amount; self diff --git a/rust/chains/tw_ton/src/signing_request/builder.rs b/rust/chains/tw_ton/src/signing_request/builder.rs index 5324546deb4..2291e4479ba 100644 --- a/rust/chains/tw_ton/src/signing_request/builder.rs +++ b/rust/chains/tw_ton/src/signing_request/builder.rs @@ -4,7 +4,7 @@ use crate::address::TonAddress; use crate::signing_request::{ - JettonTransferRequest, SigningRequest, TransferCustomRequest, TransferPayload, TransferRequest, + JettonTransferRequest, SigningRequest, TransferPayload, TransferRequest, }; use crate::wallet::{wallet_v4, wallet_v5, VersionedTonWallet}; use std::str::FromStr; @@ -98,6 +98,12 @@ impl SigningRequestBuilder { Some(input.comment.to_string()) }; + let state_init = if input.state_init.is_empty() { + None + } else { + Some(input.state_init.to_string()) + }; + let mode = u8::try_from(input.mode) .tw_err(|_| SigningErrorType::Error_invalid_params) .context("'mode' must fit uint8")?; @@ -115,6 +121,7 @@ impl SigningRequestBuilder { ton_amount: U256::from(input.amount), mode, comment, + state_init, payload, }) } @@ -128,33 +135,25 @@ impl SigningRequestBuilder { .into_tw() .context("Invalid 'response_address' address")?; + let custom_payload = if input.custom_payload.is_empty() { + None + } else { + Some(input.custom_payload.to_string()) + }; + let jetton_payload = JettonTransferRequest { query_id: input.query_id, jetton_amount: U256::from(input.jetton_amount), dest, response_address, + custom_payload, forward_ton_amount: U256::from(input.forward_amount), }; Ok(TransferPayload::JettonTransfer(jetton_payload)) } - fn custom_request(input: &Proto::CustomPayload) -> SigningResult { - let state_init = if input.state_init.is_empty() { - None - } else { - Some(input.state_init.to_string()) - }; - - let payload = if input.payload.is_empty() { - None - } else { - Some(input.payload.to_string()) - }; - - Ok(TransferPayload::Custom(TransferCustomRequest { - state_init, - payload, - })) + fn custom_request(input: &str) -> SigningResult { + Ok(TransferPayload::Custom(input.to_string())) } } diff --git a/rust/chains/tw_ton/src/signing_request/cell_creator.rs b/rust/chains/tw_ton/src/signing_request/cell_creator.rs index f2295848d90..20c7f7fb10c 100644 --- a/rust/chains/tw_ton/src/signing_request/cell_creator.rs +++ b/rust/chains/tw_ton/src/signing_request/cell_creator.rs @@ -8,7 +8,7 @@ use crate::message::payload::comment::CommentPayload; use crate::message::payload::empty::EmptyPayload; use crate::message::payload::jetton_transfer::JettonTransferPayload; use crate::signing_request::{ - JettonTransferRequest, SigningRequest, TransferCustomRequest, TransferPayload, TransferRequest, + JettonTransferRequest, SigningRequest, TransferPayload, TransferRequest, }; use std::sync::Arc; use tw_coin_entry::error::prelude::ResultContext; @@ -71,10 +71,23 @@ impl InternalMessageCreator { jetton: &JettonTransferRequest, comment: Option, ) -> CellResult { + let custom_payload_cell = if let Some(ref custom_payload) = jetton.custom_payload { + Some( + BagOfCells::parse_base64(custom_payload) + .context("Error parsing JettonTransfer custom_payload")? + .single_root() + .map(Arc::clone) + .context("custom_payload must contain only one single root")?, + ) + } else { + None + }; + let mut payload = JettonTransferPayload::new(jetton.dest.clone(), jetton.jetton_amount); payload .with_query_id(jetton.query_id) .with_response_destination(jetton.response_address.clone()) + .with_custom_payload(custom_payload_cell) .with_forward_ton_amount(jetton.forward_ton_amount); if let Some(comment) = comment { @@ -87,27 +100,16 @@ impl InternalMessageCreator { .context("Error generating Jetton Transfer payload") } - fn custom_payload(custom: &TransferCustomRequest) -> CellResult { - match custom.payload { - Some(ref payload) => BagOfCells::parse_base64(payload) - .context("Error parsing custom Transfer payload")? - .single_root() - .map(Arc::clone) - .context("Custom Transfer payload must contain only one single root"), - // Create an empty Cell payload. - None => EmptyPayload - .build() - .map(Cell::into_arc) - .context("Error generating Transfer's empty payload"), - } + fn custom_payload(payload: &str) -> CellResult { + BagOfCells::parse_base64(payload) + .context("Error parsing custom Transfer payload")? + .single_root() + .map(Arc::clone) + .context("Custom Transfer payload must contain only one single root") } fn maybe_custom_state_init(request: &TransferRequest) -> CellResult> { - let Some(TransferPayload::Custom(ref custom)) = request.payload else { - return Ok(None); - }; - - let Some(ref state_init) = custom.state_init else { + let Some(ref state_init) = request.state_init else { return Ok(None); }; diff --git a/rust/chains/tw_ton/src/signing_request/mod.rs b/rust/chains/tw_ton/src/signing_request/mod.rs index d0d0e3b05bf..e9eca9c07ca 100644 --- a/rust/chains/tw_ton/src/signing_request/mod.rs +++ b/rust/chains/tw_ton/src/signing_request/mod.rs @@ -13,7 +13,7 @@ pub enum TransferPayload { /// Jetton Transfer message payload. JettonTransfer(JettonTransferRequest), /// Custom Transfer message payload. - Custom(TransferCustomRequest), + Custom(String), } pub struct TransferRequest { @@ -27,6 +27,8 @@ pub struct TransferRequest { pub mode: u8, /// Transfer comment message. pub comment: Option, + /// Raw one-cell BoC encoded in Base64. Can be used to deploy a smart contract. + pub state_init: Option, /// Transfer payload. pub payload: Option, } @@ -42,18 +44,12 @@ pub struct JettonTransferRequest { /// Address where to send a response with confirmation of a successful transfer and the rest of the incoming message Toncoins. /// Usually the sender should get back their toncoins. pub response_address: TonAddress, + /// Optional custom payload. Can be used for mintless jetton transfers. + pub custom_payload: Option, /// Amount in nanotons to forward to recipient. Basically minimum amount - 1 nanoton should be used. pub forward_ton_amount: U256, } -pub struct TransferCustomRequest { - /// (string base64, optional): raw one-cell BoC encoded in Base64. - /// Can be used to deploy a smart contract. - pub state_init: Option, - /// (string base64, optional): raw one-cell BoC encoded in Base64. - pub payload: Option, -} - pub struct SigningRequest { /// Wallet initialized with the user's key-pair or public key. pub wallet: VersionedTonWallet, diff --git a/rust/tw_tests/tests/chains/ton/ton_sign.rs b/rust/tw_tests/tests/chains/ton/ton_sign.rs index 5437b95bb20..7b5e3024755 100644 --- a/rust/tw_tests/tests/chains/ton/ton_sign.rs +++ b/rust/tw_tests/tests/chains/ton/ton_sign.rs @@ -303,6 +303,7 @@ fn test_ton_sign_transfer_jettons() { // Send unused toncoins back to sender. response_address: "EQBaKIMq5Am2p_rfR1IFTwsNWHxBkOpLTmwUain5Fj4llTXk".into(), forward_amount: 1, + ..Proto::JettonTransfer::default() }; let transfer = Proto::Transfer { @@ -348,6 +349,7 @@ fn test_ton_sign_transfer_jettons_with_comment() { // Send unused toncoins back to sender. response_address: "EQBaKIMq5Am2p_rfR1IFTwsNWHxBkOpLTmwUain5Fj4llTXk".into(), forward_amount: 1, + ..Proto::JettonTransfer::default() }; let transfer = Proto::Transfer { @@ -394,10 +396,7 @@ fn test_ton_sign_transfer_custom_payload() { mode: Proto::SendMode::PAY_FEES_SEPARATELY as u32 | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS as u32, bounceable: true, - payload: PayloadType::custom_payload(Proto::CustomPayload { - state_init: "".into(), - payload: comment_cell("Hi there sir").into(), - }), + payload: PayloadType::custom_payload(comment_cell("Hi there sir").into()), ..Proto::Transfer::default() }; @@ -448,10 +447,10 @@ fn test_ton_sign_transfer_custom_payload_with_state_init() { mode: Proto::SendMode::PAY_FEES_SEPARATELY as u32 | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS as u32, bounceable: false, - payload: PayloadType::custom_payload(Proto::CustomPayload { - state_init: doge_state_init.into(), - payload: comment_cell("This transaction deploys Doge Chatbot contract").into(), - }), + state_init: doge_state_init.into(), + payload: PayloadType::custom_payload( + comment_cell("This transaction deploys Doge Chatbot contract").into(), + ), ..Proto::Transfer::default() }; diff --git a/rust/tw_tests/tests/chains/ton/ton_sign_wallet_v5r1.rs b/rust/tw_tests/tests/chains/ton/ton_sign_wallet_v5r1.rs index 9e5c0f5308c..62b0951a0b2 100644 --- a/rust/tw_tests/tests/chains/ton/ton_sign_wallet_v5r1.rs +++ b/rust/tw_tests/tests/chains/ton/ton_sign_wallet_v5r1.rs @@ -232,6 +232,7 @@ fn test_ton_sign_wallet_v5r1_transfer_jettons() { // Send unused toncoins back to sender. response_address: "UQCh41gQP1A4I0lnAn6yAfitDAIYpXG6UFIXqeSz1TVxNOJ_".into(), forward_amount: 1, + ..Default::default() }; let transfer = Proto::Transfer { @@ -277,6 +278,7 @@ fn test_ton_sign_wallet_v5r1_transfer_jettons_with_comment() { // Send unused toncoins back to sender. response_address: "UQCh41gQP1A4I0lnAn6yAfitDAIYpXG6UFIXqeSz1TVxNOJ_".into(), forward_amount: 1, + ..Default::default() }; let transfer = Proto::Transfer { @@ -323,10 +325,7 @@ fn test_ton_sign_wallet_v5r1_transfer_custom_payload() { mode: Proto::SendMode::PAY_FEES_SEPARATELY as u32 | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS as u32, bounceable: true, - payload: PayloadType::custom_payload(Proto::CustomPayload { - state_init: "".into(), - payload: comment_cell("Hi there sir").into(), - }), + payload: PayloadType::custom_payload(comment_cell("Hi there sir").into()), ..Proto::Transfer::default() }; @@ -377,10 +376,10 @@ fn test_ton_sign_wallet_v5r1_transfer_custom_payload_with_state_init() { mode: Proto::SendMode::PAY_FEES_SEPARATELY as u32 | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS as u32, bounceable: false, - payload: PayloadType::custom_payload(Proto::CustomPayload { - state_init: doge_state_init.into(), - payload: comment_cell("This transaction deploys Doge Chatbot contract").into(), - }), + state_init: doge_state_init.into(), + payload: PayloadType::custom_payload( + comment_cell("This transaction deploys Doge Chatbot contract").into(), + ), ..Proto::Transfer::default() }; @@ -432,3 +431,50 @@ fn test_ton_sign_wallet_v5r1_missing_required_send_mode() { assert_eq!(output.error, SigningError::Error_internal); } + +#[test] +fn test_ton_sign_wallet_v5r1_mintless_jetton() { + let private_key = "502d60b0f3327382e7d0585b789f1db9aa04907fe5cddc5c28818ec163ebf4ba"; + + let jetton_transfer = Proto::JettonTransfer { + query_id: 1, + // Transfer 0 mintless jetton to self. + jetton_amount: 0, + to_owner: "UQCh41gQP1A4I0lnAn6yAfitDAIYpXG6UFIXqeSz1TVxNOJ_".into(), + // Send unused toncoins back to sender. + response_address: "UQCh41gQP1A4I0lnAn6yAfitDAIYpXG6UFIXqeSz1TVxNOJ_".into(), + forward_amount: 1, + custom_payload: "te6ccgECNQEABJMAAQgN9gLWAQlGA6+1FWXC4ss/wvDOFwMk2bVM97AUEWqaUhh63uWfQ26nAB4CIgWBcAIDBChIAQEZG2ZqtEYGAq27TvzHdGuGrhhKoICBU+Zg9Xq/qRMHGAAdIgEgBQYiASAHCChIAQEV0tdPcZG01smq0thhsmqf9ZzE0QqpP3c+ERvuHF1JDgAbKEgBAf3dO8qdKoPys7AWvavs1wMNWCOq5XashXaRopmksx/LABsiASAJCiIBIAsMKEgBAWP0xUs9JBrfQRl1FkF2tIfIDYpwLdf3fXqMi6BqxNtmABoiASANDihIAQFOErI5E7ld/nTAgHXdGI74UH8kxIaFyAkH42P54tEC9QAYIgEgDxAoSAEBrF16Czdlg18FB467CrR6Ucwxb8H+Z1e4qDeFWbkz1WEAFyIBIBESKEgBAXeWzg9xTFO6z0FP+axi8Njuxxp0zPrAUs4vnmt/dE3xABYoSAEBEZ7KazNpaWJoInmqO4II/AfncyhMNWxh6BE2qFU7/9wAFCIBIBMUKEgBAZleZTNXbgCF+8G08kiQeDPanQtNCVakzEU3g9GKB+K2ABQiASAVFihIAQFeCM83J7sm36g24qFeEDvStahHWn6SsEk+Wii49rzBiAASIgEgFxgoSAEBfV9jrgSeiAKVqeeLliXdoLrxFWe2HK0f4SG5h4kfb8YAESIBIBkaIgEgGxwoSAEBImHhXIbOHuOnOgE5f0KLqoXDB7/ZLQQGiHysuulUq2IAECIBIB0eKEgBAXT+qb5w1+qtvbJ1Fbn8y6IhO85YfxKIgKBga6ROO/yQAA8iASAfIChIAQGoJHXWXWRQGZdP9xIUrMowhvgnf+CwKTIIOBxlDiKgcAANKEgBAZ6tCuDr89HFRz3WwwK+wW4XmkE+O7Hf+NgUDI+uqnAJAAwiASAhIihIAQHtasTLBAw7MZHpRTsKyC47E1PZ/LAtF3n2Y2b5ThX0VgALIgEgIyQiASAlJihIAQGumGRf7UXrpK12Cuvj06565IC0Kbd4i2XoG6dnqC+uQAAJKEgBAXM19HUUkz6ns7o/2x45kQ2iLj8gl3zYhrAhISEUg0O1AAgiASAnKCIBICkqKEgBAa7kNA+lev+Z5T/xqKBbO648BvnLL6/hAp1auOiZTWRhAAcoSAEBxn19AKZGAUPYWs8pTpNQrCB4Ap0KfzyjOgB1Mc9PbIUABSIBICssKEgBAWarrCPqSS6+lq6NRcrWZ2/v6bN4b6Zd3GWAtN6j8a6BAAQiASAtLiIBIC8wKEgBAXYYqhLZ1tHg+HdKd8vLmTBsojkj61ZiafXB7pOt+hEFAAMiASAxMihIAQHt8p6qBiXtz+kKcgo13Udyh7Uo8irrdKlSSY2dOdALogAAIgFIMzQoSAEByacrlqsAKiFOlv4Rp4V1gNg2i4aVPkcHJq8Vug/89k4AAABduZA/UDgjSWcCfrIB+K0MAhilcbpQUhep5LPVNXE0Q7msoAAABm4N2AAABm9VrQgoSAEByIAktH0CNxT//QZ8Vgj68CApZON9XBKDfE0D2rY8Fx4AAA==".into() + }; + + let transfer = Proto::Transfer { + dest: "UQCn2lssMz09Gn60mBnv544DgiqIX3mK5cqGEPEPKxCNbE0E".into(), // jetton wallet address + amount: 90 * 1000 * 1000, // 0.09 TON as fee + mode: Proto::SendMode::PAY_FEES_SEPARATELY as u32 + | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS as u32, + bounceable: true, + state_init: "te6ccgEBAwEAjwACATQBAghCAg7xnhv0Dyukkvyqw4buylm/aCejhQcI2fzZrbaDq8M2AMoAgBQ8awIH6gcEaSzgT9ZAPxWhgEMUrjdKCkL1PJZ6pq4mkAPpn0MdzkzH7w8jwjgGMZfR3Y2FqlpEArXYKCy3B42gyr7UVZcLiyz/C8M4XAyTZtUz3sBQRappSGHre5Z9DbqcAg==".into(), + payload: PayloadType::jetton_transfer(jetton_transfer), + ..Proto::Transfer::default() + }; + + let input = Proto::SigningInput { + private_key: private_key.decode_hex().unwrap().into(), + messages: vec![transfer], + sequence_number: 7, + expire_at: 1727346541, + wallet_version: Proto::WalletVersion::WALLET_V5_R1, + ..Proto::SigningInput::default() + }; + + let mut signer = AnySignerHelper::::default(); + let output = signer.sign(CoinType::TON, input); + + assert_eq!(output.error, SigningError::OK, "{}", output.error_message); + // Successfully broadcasted: https://tonviewer.com/transaction/70f347338b3e0d33feb285a0cc7300d216b6011462ed7e76c6395bcca7abc649 + assert_eq_boc(&output.encoded, "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"); + assert_eq!( + output.hash.to_hex(), + "70f347338b3e0d33feb285a0cc7300d216b6011462ed7e76c6395bcca7abc649" + ); +} diff --git a/src/proto/TheOpenNetwork.proto b/src/proto/TheOpenNetwork.proto index 092ec3bcd9b..4ef1ca11ac4 100644 --- a/src/proto/TheOpenNetwork.proto +++ b/src/proto/TheOpenNetwork.proto @@ -43,12 +43,16 @@ message Transfer { // If the address is bounceable bool bounceable = 5; + // Optional raw one-cell BoC encoded in Base64. + // Can be used to deploy a smart contract. + string state_init = 6; + // One of the Transfer message payloads (optional). oneof payload { // Jetton transfer payload. - JettonTransfer jetton_transfer = 6; - // TON transfer with custom stateInit and payload (contract call). - CustomPayload custom_payload = 7; + JettonTransfer jetton_transfer = 7; + // TON transfer with custom payload (contract call). Raw one-cell BoC encoded in Base64. + string custom_payload = 8; } } @@ -67,15 +71,10 @@ message JettonTransfer { // Amount in nanotons to forward to recipient. Basically minimum amount - 1 nanoton should be used uint64 forward_amount = 5; -} - -message CustomPayload { - // (string base64, optional): raw one-cell BoC encoded in Base64. - // Can be used to deploy a smart contract. - string state_init = 1; - // (string base64, optional): raw one-cell BoC encoded in Base64. - string payload = 2; + // Optional raw one-cell BoC encoded in Base64. + // Can be used in the case of mintless jetton transfers. + string custom_payload = 6; } message SigningInput { diff --git a/swift/Tests/Blockchains/TheOpenNetworkTests.swift b/swift/Tests/Blockchains/TheOpenNetworkTests.swift index f27e3a2fbd8..797ae8334e0 100644 --- a/swift/Tests/Blockchains/TheOpenNetworkTests.swift +++ b/swift/Tests/Blockchains/TheOpenNetworkTests.swift @@ -153,18 +153,14 @@ class TheOpenNetworkTests: XCTestCase { // "This transaction deploys Doge Chatbot contract" let commentPayload = "te6cckEBAQEANAAAZAAAAABUaGlzIHRyYW5zYWN0aW9uIGRlcGxveXMgRG9nZSBDaGF0Ym90IGNvbnRyYWN0v84vSg==" - let customPayload = TheOpenNetworkCustomPayload.with { - $0.stateInit = dogeChatbotStateInit - $0.payload = commentPayload - } - let transfer = TheOpenNetworkTransfer.with { $0.dest = dogeChatbotDeployingAddress // 0.069 TON $0.amount = 69_000_000 $0.mode = UInt32(TheOpenNetworkSendMode.payFeesSeparately.rawValue | TheOpenNetworkSendMode.ignoreActionPhaseErrors.rawValue) $0.bounceable = false - $0.customPayload = customPayload + $0.stateInit = dogeChatbotStateInit + $0.customPayload = commentPayload } let input = TheOpenNetworkSigningInput.with {