From 6f35a5d6c64c04d017a78bbf6848bbb97d536754 Mon Sep 17 00:00:00 2001
From: Max Voloshinskii <me@voloshinskii.ru>
Date: Wed, 22 May 2024 02:00:14 +0300
Subject: [PATCH] Support more Getgems methods

---
 .../@core-js/src/service/contractService.ts   |  2 ++
 .../src/service/transactionService.ts         | 27 ++++++++++++++-----
 .../NFTOperations/Modals/SignRawModal.tsx     | 21 ++++++++-------
 packages/mobile/src/tonconnect/TonConnect.ts  |  7 ++++-
 4 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/packages/@core-js/src/service/contractService.ts b/packages/@core-js/src/service/contractService.ts
index 0f706bbca..e019fcd9c 100644
--- a/packages/@core-js/src/service/contractService.ts
+++ b/packages/@core-js/src/service/contractService.ts
@@ -14,6 +14,8 @@ export enum OpCodes {
   JETTON_TRANSFER = 0xf8a7ea5,
   NFT_TRANSFER = 0x5fcc3d14,
   STONFI_SWAP = 0x25938561,
+  PUT_ON_SALE = 0x00000001,
+  REMOVE_FROM_SALE = 0x00000003,
 }
 
 export enum WalletVersion {
diff --git a/packages/@core-js/src/service/transactionService.ts b/packages/@core-js/src/service/transactionService.ts
index b937f9883..d801475f5 100644
--- a/packages/@core-js/src/service/transactionService.ts
+++ b/packages/@core-js/src/service/transactionService.ts
@@ -24,6 +24,8 @@ export interface TransferParams {
   messages: MessageRelaxed[];
 }
 
+export const ALLOWED_BATTERY_DOMAINS = ['getgems.io'];
+
 export function tonAddress(address: AnyAddress) {
   if (typeof address === 'string') {
     return Address.parse(address);
@@ -111,24 +113,37 @@ export class TransactionService {
     supportedTransactions: Record<BatterySupportedTransaction, boolean>,
   ) {
     const slice = payload.beginParse();
+    if (slice.remainingBits < 32) {
+      return true;
+    }
     const opCode = slice.loadUint(32);
 
     switch (opCode) {
+      case OpCodes.PUT_ON_SALE:
+        return supportedTransactions[BatterySupportedTransaction.NFTSale];
+      case OpCodes.REMOVE_FROM_SALE:
+        return supportedTransactions[BatterySupportedTransaction.NFTSale];
       case OpCodes.STONFI_SWAP:
         return supportedTransactions[BatterySupportedTransaction.Swap];
       case OpCodes.NFT_TRANSFER:
         if (slice.remainingRefs) {
-          return TransactionService.shouldRelayPayload(
-            slice.loadRef(),
-            supportedTransactions,
+          const refsArr = new Array(slice.remainingRefs);
+          while (slice.remainingRefs) {
+            refsArr.push(slice.loadRef());
+          }
+          return refsArr.every((ref) =>
+            TransactionService.shouldRelayPayload(ref, supportedTransactions),
           );
         }
         return supportedTransactions[BatterySupportedTransaction.NFT];
       case OpCodes.JETTON_TRANSFER:
         if (slice.remainingRefs) {
-          return TransactionService.shouldRelayPayload(
-            slice.loadRef(),
-            supportedTransactions,
+          const refsArr = new Array(slice.remainingRefs);
+          while (slice.remainingRefs) {
+            refsArr.push(slice.loadRef());
+          }
+          return refsArr.every((ref) =>
+            TransactionService.shouldRelayPayload(ref, supportedTransactions),
           );
         }
         return supportedTransactions[BatterySupportedTransaction.Jetton];
diff --git a/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx b/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx
index e29fafa7d..b7fb13ca6 100644
--- a/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx
+++ b/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx
@@ -380,6 +380,18 @@ export const openSignRawModal = async (
       await TonConnectRemoteBridge.closeOtherTransactions();
     }
 
+    let shouldRelayTransaction: boolean = false;
+    try {
+      shouldRelayTransaction = options.experimentalWithBattery
+        ? TransactionService.shouldRelayPayloads(
+            params.messages
+              .map((message) => message.payload)
+              .filter((message) => !!message) as string[],
+            tk.wallet.battery.state.data.supportedTransactions,
+          )
+        : false;
+    } catch {}
+
     let consequences: MessageConsequences | null = null;
     let isBattery = false;
     try {
@@ -393,15 +405,6 @@ export const openSignRawModal = async (
         seqno: await getWalletSeqno(wallet),
       });
 
-      const shouldRelayTransaction = options.experimentalWithBattery
-        ? TransactionService.shouldRelayPayloads(
-            params.messages
-              .map((message) => message.payload)
-              .filter((message) => !!message) as string[],
-            tk.wallet.battery.state.data.supportedTransactions,
-          )
-        : false;
-
       const totalAmount = calculateMessageTransferAmount(params.messages);
       const { emulateResult, battery } = await emulateBoc(
         boc,
diff --git a/packages/mobile/src/tonconnect/TonConnect.ts b/packages/mobile/src/tonconnect/TonConnect.ts
index d4b6209ce..16bc7fbd3 100644
--- a/packages/mobile/src/tonconnect/TonConnect.ts
+++ b/packages/mobile/src/tonconnect/TonConnect.ts
@@ -42,6 +42,7 @@ import { tk } from '$wallet';
 import { TonConnectRemoteBridge } from './TonConnectRemoteBridge';
 import { WithWalletIdentifier } from '$wallet/WalletTypes';
 import { getDomainFromURL } from '$utils';
+import { ALLOWED_BATTERY_DOMAINS } from '@tonkeeper/core';
 
 class TonConnectService {
   checkProtocolVersionCapability(protocolVersion: number) {
@@ -310,6 +311,10 @@ class TonConnectService {
         );
       }
 
+      const isBatteryEnabled = ALLOWED_BATTERY_DOMAINS.includes(
+        getDomainFromURL(senderUrl),
+      );
+
       const { valid_until, messages } = params;
 
       if (valid_until < getTimeSec()) {
@@ -332,7 +337,7 @@ class TonConnectService {
         const openModalResult = await openSignRawModal(
           txParams,
           {
-            experimentalWithBattery: true,
+            experimentalWithBattery: isBatteryEnabled,
             expires_sec: valid_until,
             response_options: {
               broadcast: false,