Skip to content

Commit

Permalink
feature(mobile): Dynamic forward amount for NFT (#668)
Browse files Browse the repository at this point in the history
* feature(mobile): Dynamic forward amount for NFT

* Cleanup
  • Loading branch information
voloshinskii authored Jan 12, 2024
1 parent a797ab1 commit 4bf2e29
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 17 deletions.
1 change: 1 addition & 0 deletions packages/@core-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { TonAPI, useTonAPI, TonAPIProvider } from './TonAPI';
export * from './formatters/Address';
export * from './formatters/DNS';

export * from './utils/constants';
export * from './utils/AmountFormatter/FiatCurrencyConfig';
export * from './utils/AmountFormatter';
export * from './utils/network';
Expand Down
4 changes: 4 additions & 0 deletions packages/@core-js/src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { toNano } from '@ton/core';

export const ONE_TON = toNano('1');
export const BASE_FORWARD_AMOUNT = toNano('0.05');
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export async function checkIsInsufficient(amount: string | number) {
return { insufficient: false, balance: null };
}

export const openInsufficientFundsModal = async (params: InsufficientFundsParams) => {
export const openInsufficientFundsModal = (params: InsufficientFundsParams) => {
push('SheetsProvider', {
$$action: SheetActions.ADD,
component: InsufficientFundsModal,
Expand Down
80 changes: 64 additions & 16 deletions packages/mobile/src/core/NFTSend/NFTSend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,29 @@ import { NFTSendSteps } from '$core/NFTSend/types';
import { ConfirmStep } from '$core/NFTSend/steps/ConfirmStep/ConfirmStep';
import { useNFT } from '$hooks/useNFT';
import {
BASE_FORWARD_AMOUNT,
ContractService,
contractVersionsMap,
ONE_TON,
TransactionService,
} from '@tonkeeper/core';
import { tk, tonapi } from '@tonkeeper/shared/tonkeeper';
import { getWalletSeqno } from '@tonkeeper/shared/utils/wallet';
import { getWalletSeqno, setBalanceForEmulation } from '@tonkeeper/shared/utils/wallet';
import { Buffer } from 'buffer';
import { MessageConsequences } from '@tonkeeper/core/src/TonAPI';
import { internal, MessageRelaxed, toNano } from '@ton/core';
import { internal, toNano } from '@ton/core';
import BigNumber from 'bignumber.js';
import { Ton } from '$libs/Ton';
import { delay } from '$utils';
import { Toast } from '$store';
import axios from 'axios';
import { useWallet } from '$hooks/useWallet';
import { useUnlockVault } from '$core/ModalContainer/NFTOperations/useUnlockVault';
import {
checkIsInsufficient,
openInsufficientFundsModal,
} from '$core/ModalContainer/InsufficientFunds/InsufficientFunds';
import { CanceledActionError } from '$core/Send/steps/ConfirmStep/ActionErrors';
import { Keyboard } from 'react-native';

interface Props {
Expand Down Expand Up @@ -69,7 +76,6 @@ export const NFTSend: FC<Props> = (props) => {
const [recipient, setRecipient] = useState<SendRecipient | null>(null);
const [recipientAccountInfo, setRecipientAccountInfo] =
useState<AccountWithPubKey | null>(null);
const messages = useRef<MessageRelaxed[]>([]);

const handleBack = useCallback(() => stepViewRef.current?.goBack(), []);

Expand All @@ -95,7 +101,7 @@ export const NFTSend: FC<Props> = (props) => {
const nftTransferMessages = [
internal({
to: nftAddress,
value: toNano('1'),
value: ONE_TON,
body: ContractService.createNftTransferBody({
queryId: Date.now(),
newOwnerAddress: recipient!.address,
Expand All @@ -116,8 +122,12 @@ export const NFTSend: FC<Props> = (props) => {
seqno: await getWalletSeqno(),
secretKey: Buffer.alloc(64),
});
const response = await tonapi.wallet.emulateMessageToWallet({ boc });
messages.current = nftTransferMessages;

const response = await tonapi.wallet.emulateMessageToWallet({
boc,
params: [setBalanceForEmulation(toNano('2'))], // Emulate with higher balance to calculate fair amount to send
});

setConsequences(response);

Keyboard.dismiss();
Expand All @@ -137,19 +147,55 @@ export const NFTSend: FC<Props> = (props) => {
}
}, [comment, nftAddress, recipient, wallet.ton]);

const total = useMemo(() => {
const extra = new BigNumber(Ton.fromNano(consequences?.event.extra ?? 0));

return { amount: extra.abs().toString(), isRefund: !extra.isNegative() };
}, [consequences?.event.extra]);

const sendTx = useCallback(async () => {
try {
setSending(true);

const vault = await unlockVault();
const privateKey = await vault.getTonPrivateKey();

const totalAmount = total.isRefund
? BASE_FORWARD_AMOUNT
: BigInt(Math.abs(consequences?.event.extra!)) + BASE_FORWARD_AMOUNT;

const checkResult = await checkIsInsufficient(totalAmount.toString());
if (checkResult.insufficient) {
openInsufficientFundsModal({
totalAmount: totalAmount.toString(),
balance: checkResult.balance,
});

await delay(200);
throw new CanceledActionError();
}

const nftTransferMessages = [
internal({
to: nftAddress,
value: totalAmount,
body: ContractService.createNftTransferBody({
queryId: Date.now(),
newOwnerAddress: recipient!.address,
excessesAddress: tk.wallet.address.ton.raw,
forwardBody: comment,
}),
bounce: true,
}),
];

const contract = ContractService.getWalletContract(
contractVersionsMap[vault.getVersion() ?? 'v4R2'],
Buffer.from(vault.tonPublicKey),
contractVersionsMap[wallet.ton.version ?? 'v4R2'],
Buffer.from(await wallet.ton.getTonPublicKey()),
);

const boc = TransactionService.createTransfer(contract, {
messages: messages.current,
messages: nftTransferMessages,
seqno: await getWalletSeqno(),
sendMode: 3,
secretKey: Buffer.from(privateKey),
Expand All @@ -166,13 +212,15 @@ export const NFTSend: FC<Props> = (props) => {
} finally {
setSending(false);
}
}, [unlockVault]);

const total = useMemo(() => {
const fee = new BigNumber(Ton.fromNano(consequences?.event.extra ?? 0));

return { amount: fee.abs().toString(), isRefund: !fee.isNegative() };
}, [consequences?.event.extra]);
}, [
comment,
consequences?.event.extra,
nftAddress,
recipient,
total.isRefund,
unlockVault,
wallet.ton,
]);

return (
<>
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/utils/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ export async function getWalletSeqno() {
return 0;
}
}

export function setBalanceForEmulation(balance: bigint) {
return { balance: Number(balance), address: tk.wallet.address.ton.raw };
}

0 comments on commit 4bf2e29

Please sign in to comment.