diff --git a/public/_locales/de/messages.json b/public/_locales/de/messages.json index 55d867a..82fb6f4 100644 --- a/public/_locales/de/messages.json +++ b/public/_locales/de/messages.json @@ -1859,5 +1859,25 @@ }, "messageFrom": { "message": "Nachricht von" + }, + "addTreasuryAccount": { + "message": "Treasury-Konto hinzufügen" + }, + "originationOf": { + "message": "von $contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, + "p2pMessage": { + "message": "P2P-Nachricht" + }, + "tokenIssuance": { + "message": "Token-Erstellung" + }, + "tokenMint": { + "message": "Münzprägung" } } \ No newline at end of file diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 39698bb..7a36bc5 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -1062,6 +1062,14 @@ "origination": { "message": "Contract Creation" }, + "originationOf": { + "message": "of $contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, "other": { "message": "Other" }, @@ -1862,5 +1870,14 @@ }, "messageFrom": { "message": "Message from" + }, + "tokenIssuance": { + "message": "Token Creation" + }, + "tokenMint": { + "message": "Token Minting" + }, + "addTreasuryAccount": { + "message": "Add Treasury Account" } -} +} \ No newline at end of file diff --git a/public/_locales/es/messages.json b/public/_locales/es/messages.json index 24d1869..6e9c26f 100644 --- a/public/_locales/es/messages.json +++ b/public/_locales/es/messages.json @@ -1859,5 +1859,25 @@ }, "messageFrom": { "message": "Mensaje de" + }, + "addTreasuryAccount": { + "message": "Añadir cuenta de tesorería" + }, + "originationOf": { + "message": "de $contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, + "p2pMessage": { + "message": "Mensaje P2P" + }, + "tokenIssuance": { + "message": "Creación de fichas" + }, + "tokenMint": { + "message": "Acuñación de fichas" } } \ No newline at end of file diff --git a/public/_locales/pt_BR/messages.json b/public/_locales/pt_BR/messages.json index 94f47f8..d011353 100644 --- a/public/_locales/pt_BR/messages.json +++ b/public/_locales/pt_BR/messages.json @@ -1859,5 +1859,25 @@ }, "messageFrom": { "message": "Mensagem de" + }, + "addTreasuryAccount": { + "message": "Adicionar conta de tesouraria" + }, + "originationOf": { + "message": "de $contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, + "p2pMessage": { + "message": "Mensagem P2P" + }, + "tokenIssuance": { + "message": "Criação de token" + }, + "tokenMint": { + "message": "Cunhagem de Token" } } \ No newline at end of file diff --git a/public/_locales/ru/messages.json b/public/_locales/ru/messages.json index 5c9b476..3a2cdcd 100644 --- a/public/_locales/ru/messages.json +++ b/public/_locales/ru/messages.json @@ -1859,5 +1859,25 @@ }, "messageFrom": { "message": "Сообщение от" + }, + "addTreasuryAccount": { + "message": "Добавить казначейский счет" + }, + "originationOf": { + "message": "$contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, + "p2pMessage": { + "message": "P2P-сообщение" + }, + "tokenIssuance": { + "message": "Создание токена" + }, + "tokenMint": { + "message": "Чеканка токенов" } } \ No newline at end of file diff --git a/public/_locales/th/messages.json b/public/_locales/th/messages.json index 8229fcc..d98248d 100644 --- a/public/_locales/th/messages.json +++ b/public/_locales/th/messages.json @@ -1859,5 +1859,25 @@ }, "messageFrom": { "message": "ข้อความจาก" + }, + "addTreasuryAccount": { + "message": "เพิ่มบัญชีธนารักษ์" + }, + "originationOf": { + "message": "ของ $contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, + "p2pMessage": { + "message": "ข้อความ P2P" + }, + "tokenIssuance": { + "message": "การสร้างโทเค็น" + }, + "tokenMint": { + "message": "เหรียญกษาปณ์" } } \ No newline at end of file diff --git a/public/_locales/uk/messages.json b/public/_locales/uk/messages.json index b997629..3198c8c 100644 --- a/public/_locales/uk/messages.json +++ b/public/_locales/uk/messages.json @@ -1859,5 +1859,25 @@ }, "messageFrom": { "message": "Повідомлення від" + }, + "addTreasuryAccount": { + "message": "Додати казначейський рахунок" + }, + "originationOf": { + "message": "$contract$", + "placeholders": { + "constract": { + "content": "$1" + } + } + }, + "p2pMessage": { + "message": "P2P-повідомлення" + }, + "tokenIssuance": { + "message": "Створення токена" + }, + "tokenMint": { + "message": "Чеканка токенів" } } \ No newline at end of file diff --git a/src/app/templates/SignumActivity/Time.tsx b/src/app/atoms/Time.tsx similarity index 100% rename from src/app/templates/SignumActivity/Time.tsx rename to src/app/atoms/Time.tsx diff --git a/src/app/pages/ImportAccount/WatchOnlyForm.tsx b/src/app/pages/ImportAccount/WatchOnlyForm.tsx index 2d3911b..e11920a 100644 --- a/src/app/pages/ImportAccount/WatchOnlyForm.tsx +++ b/src/app/pages/ImportAccount/WatchOnlyForm.tsx @@ -10,6 +10,7 @@ import NoSpaceField from 'app/atoms/NoSpaceField'; import { T, t } from 'lib/i18n/react'; import { isSignumAddress, + SMART_CONTRACT_PUBLIC_KEY, useSignum, useSignumAccountPrefix, useSignumAliasResolver, @@ -21,8 +22,6 @@ interface WatchOnlyFormData { address: string; } -const SmartContractPk = '0000000000000000000000000000000000000000000000000000000000000000'; - export const WatchOnlyForm: FC = () => { const { importWatchOnlyAccount } = useTempleClient(); const signum = useSignum(); @@ -86,7 +85,7 @@ export const WatchOnlyForm: FC = () => { } // @ts-ignore const publicKey = acc.publicKey; - if (!publicKey || publicKey === SmartContractPk) { + if (!publicKey || publicKey === SMART_CONTRACT_PUBLIC_KEY) { throw new Error(t('cannotImportWatchAccount')); } return publicKey; diff --git a/src/app/templates/SignumActivity/ActivityItem.tsx b/src/app/templates/SignumActivity/ActivityItem.tsx index 905436f..2a30c8d 100644 --- a/src/app/templates/SignumActivity/ActivityItem.tsx +++ b/src/app/templates/SignumActivity/ActivityItem.tsx @@ -6,13 +6,13 @@ import classNames from 'clsx'; import formatDistanceToNow from 'date-fns/formatDistanceToNow'; import OpenInExplorerChip from 'app/atoms/OpenInExplorerChip'; +import Time from 'app/atoms/Time'; import HashChip from 'app/templates/HashChip'; import { getDateFnsLocale, t } from 'lib/i18n/react'; import { parseTransaction, parseAmountDiffs } from 'lib/temple/activity'; -import { useSignumAssetMetadata, useSignumExplorerBaseUrls } from 'lib/temple/front'; +import { useSignumAccountPrefix, useSignumAssetMetadata, useSignumExplorerBaseUrls } from 'lib/temple/front'; import MoneyDiffView from './MoneyDiffView'; -import Time from './Time'; import TxItem from './TxItem'; type ActivityItemProps = { @@ -24,12 +24,16 @@ type ActivityItemProps = { const ActivityItem = memo(({ accountId, transaction, className }) => { const { transaction: explorerBaseUrl } = useSignumExplorerBaseUrls(); const metadata = useSignumAssetMetadata(); + const prefix = useSignumAccountPrefix(); const { transaction: txId, timestamp } = transaction; const dateFnsLocale = getDateFnsLocale(); const moneyDiff = useMemo(() => parseAmountDiffs(transaction, accountId)[0], [transaction, accountId]); const feeAmount = useMemo(() => Amount.fromPlanck(transaction.feeNQT!).getSigna(), [transaction.feeNQT]); - const parsedTransaction = useMemo(() => parseTransaction(transaction, accountId), [transaction, accountId]); + const parsedTransaction = useMemo( + () => parseTransaction(transaction, accountId, prefix), + [transaction, accountId, prefix] + ); const isPending = transaction.blockTimestamp === undefined; const transactionStatus = useMemo(() => { const content = isPending ? 'pending' : 'applied'; @@ -69,7 +73,7 @@ const ActivityItem = memo(({ accountId, transaction, classNam
-
+
{feeAmount} {metadata.symbol}
diff --git a/src/app/templates/SignumActivity/TxItem.tsx b/src/app/templates/SignumActivity/TxItem.tsx index b9d6fb2..abd5dd5 100644 --- a/src/app/templates/SignumActivity/TxItem.tsx +++ b/src/app/templates/SignumActivity/TxItem.tsx @@ -5,7 +5,6 @@ import classNames from 'clsx'; import { T, TProps } from 'lib/i18n/react'; import { TransactionItem, TransactionItemType } from 'lib/temple/activity'; -import { ReactComponent as ClipboardIcon } from '../../icons/clipboard.svg'; import HashChip from '../HashChip'; type TxItemProps = { @@ -34,21 +33,23 @@ const TxItemComponent = memo(({ item }) => { return { base: ( <> + 🤖  - ) + ), + argsI18nKey: 'originationOf', + args: [item.contract] }; - // TODO: messages to smart contracts - problem: it has to be async to figure out if receiver is a contract case TransactionItemType.Interaction: return { base: ( <> - + ⚙  ), argsI18nKey: 'interactionWithContract', - args: [item.with] + args: [item.contract] }; case TransactionItemType.TransferFrom: @@ -72,14 +73,41 @@ const TxItemComponent = memo(({ item }) => { argsI18nKey: 'transferToSmb', args: [item.to] }; - + case TransactionItemType.MessageFrom: + return { + base: ( + <> + ↓{item.isEncrypted ? '🔐' : '✉'} + + ), + argsI18nKey: 'transferFromSmb', + args: [item.from] + }; + case TransactionItemType.MessageTo: + return { + base: ( + <> + ↑{item.isEncrypted ? '🔐' : '✉'} + + ), + argsI18nKey: 'transferToSmb', + args: [item.to] + }; + case TransactionItemType.SelfUpdate: + return { + base: ( + <> + {item.prefix} + + ) + }; case TransactionItemType.Other: return { - // TODO: once we have proper naming, need to adjust this. - base: item.name - .split('_') - .map(w => `${w.charAt(0).toUpperCase()}${w.substring(1)}`) - .join(' ') + base: ( + <> + + + ) }; } })(); diff --git a/src/app/templates/SignumP2PMessages/P2PMessageItem.tsx b/src/app/templates/SignumP2PMessages/P2PMessageItem.tsx index c1712dd..3ccad91 100644 --- a/src/app/templates/SignumP2PMessages/P2PMessageItem.tsx +++ b/src/app/templates/SignumP2PMessages/P2PMessageItem.tsx @@ -7,6 +7,7 @@ import classNames from 'clsx'; import formatDistanceToNow from 'date-fns/formatDistanceToNow'; import OpenInExplorerChip from 'app/atoms/OpenInExplorerChip'; +import Time from 'app/atoms/Time'; import { ReactComponent as CopyIcon } from 'app/icons/copy.svg'; import { ReactComponent as LockAltIcon } from 'app/icons/lock-alt.svg'; import HashChip from 'app/templates/HashChip'; @@ -15,8 +16,6 @@ import { useAccount, useSignumExplorerBaseUrls, useTempleClient } from 'lib/temp import useCopyToClipboard from 'lib/ui/useCopyToClipboard'; import useSafeState from 'lib/ui/useSafeState'; -import Time from './Time'; - type Props = { accountId: string; message: Transaction; @@ -98,7 +97,8 @@ const P2PMessageItem = memo(({ accountId, message }) => { )} /> - + {isEncrypted && revealedMessage && } + {!isEncrypted && }
diff --git a/src/app/templates/SignumP2PMessages/Time.tsx b/src/app/templates/SignumP2PMessages/Time.tsx deleted file mode 100644 index 16db790..0000000 --- a/src/app/templates/SignumP2PMessages/Time.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -type TimeProps = { - children: () => React.ReactElement; -}; - -const Time: React.FC = ({ children }) => { - const [value, setValue] = useState(children); - - useEffect(() => { - const interval = setInterval(() => { - setValue(children()); - }, 5_000); - - return () => { - clearInterval(interval); - }; - }, [setValue, children]); - - return value; -}; - -export default Time; diff --git a/src/app/templates/SignumP2PMessages/TxItem.tsx b/src/app/templates/SignumP2PMessages/TxItem.tsx deleted file mode 100644 index b9d6fb2..0000000 --- a/src/app/templates/SignumP2PMessages/TxItem.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React, { memo } from 'react'; - -import classNames from 'clsx'; - -import { T, TProps } from 'lib/i18n/react'; -import { TransactionItem, TransactionItemType } from 'lib/temple/activity'; - -import { ReactComponent as ClipboardIcon } from '../../icons/clipboard.svg'; -import HashChip from '../HashChip'; - -type TxItemProps = { - item: TransactionItem; - className?: string; -}; - -const TxItem = memo(({ item, className }) => { - return ( -
- -
- ); -}); - -export default TxItem; - -type TxItemComponentProps = { - item: TransactionItem; -}; - -const TxItemComponent = memo(({ item }) => { - const toRender = (() => { - switch (item.type) { - case TransactionItemType.Origination: - return { - base: ( - <> - - - ) - }; - // TODO: messages to smart contracts - problem: it has to be async to figure out if receiver is a contract - case TransactionItemType.Interaction: - return { - base: ( - <> - - - - ), - argsI18nKey: 'interactionWithContract', - args: [item.with] - }; - - case TransactionItemType.TransferFrom: - return { - base: ( - <> - ↓ - - ), - argsI18nKey: 'transferFromSmb', - args: [item.from] - }; - - case TransactionItemType.TransferTo: - return { - base: ( - <> - ↑ - - ), - argsI18nKey: 'transferToSmb', - args: [item.to] - }; - - case TransactionItemType.Other: - return { - // TODO: once we have proper naming, need to adjust this. - base: item.name - .split('_') - .map(w => `${w.charAt(0).toUpperCase()}${w.substring(1)}`) - .join(' ') - }; - } - })(); - - return ( -
-
{toRender.base}
- - {toRender.argsI18nKey && } -
- ); -}); - -type TxItemArgsProps = { - i18nKey: TProps['id']; - args: string[]; - className?: string; -}; - -const TxItemArgs = memo(({ i18nKey, args, className }) => ( - - ( - - - {index === args.length - 1 ? null : ', '} - - ))} - /> - -)); diff --git a/src/app/templates/SignumSendForm/SendForm.tsx b/src/app/templates/SignumSendForm/SendForm.tsx index c06ef37..4e3974f 100644 --- a/src/app/templates/SignumSendForm/SendForm.tsx +++ b/src/app/templates/SignumSendForm/SendForm.tsx @@ -19,6 +19,7 @@ import { toLocalFixed } from 'lib/i18n/numbers'; import { T, t } from 'lib/i18n/react'; import { isSignumAddress, + SMART_CONTRACT_PUBLIC_KEY, useAccount, useBalance, useSignum, @@ -49,7 +50,6 @@ type FormProps = { }; const MinimumFee = Amount.fromPlanck(FeeQuantPlanck).getSigna(); -const SmartContractPk = '0000000000000000000000000000000000000000000000000000000000000000'; export const SendForm: FC = ({ setOperation, onAddContactRequested }) => { const messageFormRef = useRef(); @@ -118,7 +118,7 @@ export const SendForm: FC = ({ setOperation, onAddContactRequested }) const toResolved = useMemo(() => { try { - if (resolvedPublicKey && resolvedPublicKey !== SmartContractPk) { + if (resolvedPublicKey && resolvedPublicKey !== SMART_CONTRACT_PUBLIC_KEY) { return Address.create(resolvedPublicKey).getNumericId(); } return Address.create(toValue).getNumericId(); @@ -369,7 +369,7 @@ export const SendForm: FC = ({ setOperation, onAddContactRequested }) {toResolved && (
{t('resolvedAddress')}: - {resolvedPublicKey === SmartContractPk ? ( + {resolvedPublicKey === SMART_CONTRACT_PUBLIC_KEY ? ( 🤖 {Address.create(toResolved, prefix).getReedSolomonAddress()} ) : ( {Address.create(toResolved, prefix).getReedSolomonAddress()} @@ -424,7 +424,7 @@ export const SendForm: FC = ({ setOperation, onAddContactRequested }) diff --git a/src/app/templates/SignumSendForm/SendP2PMessageForm.tsx b/src/app/templates/SignumSendForm/SendP2PMessageForm.tsx index 0cb8ddf..d1ac68c 100644 --- a/src/app/templates/SignumSendForm/SendP2PMessageForm.tsx +++ b/src/app/templates/SignumSendForm/SendP2PMessageForm.tsx @@ -15,6 +15,7 @@ import { MessageForm, MessageFormData } from 'app/templates/SignumSendForm/Messa import { T, t } from 'lib/i18n/react'; import { isSignumAddress, + SMART_CONTRACT_PUBLIC_KEY, useAccount, useSignum, useSignumAccountPrefix, @@ -42,7 +43,6 @@ type FormProps = { }; const MinimumFee = Amount.fromPlanck(FeeQuantPlanck).getSigna(); -const SmartContractPk = '0000000000000000000000000000000000000000000000000000000000000000'; export const SendP2PMessageForm: FC = ({ setOperation, onAddContactRequested }) => { const messageFormRef = useRef(); @@ -106,7 +106,7 @@ export const SendP2PMessageForm: FC = ({ setOperation, onAddContactRe const toResolved = useMemo(() => { try { - if (resolvedPublicKey && resolvedPublicKey !== SmartContractPk) { + if (resolvedPublicKey && resolvedPublicKey !== SMART_CONTRACT_PUBLIC_KEY) { return Address.create(resolvedPublicKey).getNumericId(); } return Address.create(toValue).getNumericId(); @@ -304,7 +304,7 @@ export const SendP2PMessageForm: FC = ({ setOperation, onAddContactRe {toResolved && (
{t('resolvedAddress')}: - {resolvedPublicKey === SmartContractPk ? ( + {resolvedPublicKey === SMART_CONTRACT_PUBLIC_KEY ? ( 🤖 {Address.create(toResolved, prefix).getReedSolomonAddress()} ) : ( {Address.create(toResolved, prefix).getReedSolomonAddress()} @@ -327,7 +327,7 @@ export const SendP2PMessageForm: FC = ({ setOperation, onAddContactRe diff --git a/src/lib/temple/activity/parseTransaction.ts b/src/lib/temple/activity/parseTransaction.ts index 9f179d2..b39c6e7 100644 --- a/src/lib/temple/activity/parseTransaction.ts +++ b/src/lib/temple/activity/parseTransaction.ts @@ -1,38 +1,110 @@ import { Address, Transaction, + TransactionArbitrarySubtype, + TransactionAssetSubtype, TransactionEscrowSubtype, + TransactionMiningSubtype, TransactionSmartContractSubtype, TransactionType } from '@signumjs/core'; -import { TransactionItem, TransactionItemType } from './types'; +import { SMART_CONTRACT_PUBLIC_KEY } from 'lib/temple/metadata'; + +import { SelfUpdateItem, TransactionItem, TransactionItemType } from './types'; function isPayment(tx: Transaction): boolean { return ( tx.type === TransactionType.Payment || - (tx.type === TransactionType.Escrow && tx.subtype === TransactionEscrowSubtype.SubscriptionPayment) || - (tx.type === TransactionType.AT && tx.subtype === TransactionSmartContractSubtype.SmartContractPayment) + (tx.type === TransactionType.Asset && tx.subtype === TransactionAssetSubtype.AssetTransfer) || + (tx.type === TransactionType.Asset && tx.subtype === 8) || // distribution to token holders + (tx.type === TransactionType.Asset && tx.subtype === 9) || // asset multi transfer + (tx.type === TransactionType.Escrow && tx.subtype === TransactionEscrowSubtype.SubscriptionPayment) ); } +function isMessage(tx: Transaction): boolean { + return tx.type === TransactionType.Arbitrary && tx.subtype === TransactionArbitrarySubtype.Message; +} + +function isSelfUpdate(tx: Transaction): boolean { + return tx.type === TransactionType.Arbitrary && tx.subtype === TransactionArbitrarySubtype.AccountInfo; +} + +function getSelfUpdateItem(tx: Transaction): SelfUpdateItem { + let item: SelfUpdateItem = { + type: TransactionItemType.SelfUpdate, + prefix: '', + i18nKey: '' + }; + + if (tx.type === TransactionType.Arbitrary && tx.subtype === TransactionArbitrarySubtype.AccountInfo) { + item.prefix = 'ℹ'; + item.i18nKey = 'updateAccountInfo'; + } else if (tx.type === TransactionType.Mining && tx.subtype === TransactionMiningSubtype.AddCommitment) { + item.prefix = '⚒'; + item.i18nKey = 'addCommitment'; + } else if (tx.type === TransactionType.Mining && tx.subtype === TransactionMiningSubtype.RemoveCommitment) { + item.prefix = '⚒'; + item.i18nKey = 'removeCommitment'; + } else if (tx.type === TransactionType.Mining && tx.subtype === TransactionMiningSubtype.RewardRecipientAssignment) { + item.prefix = '⚒'; + item.i18nKey = 'joinPool'; + } else if (tx.type === TransactionType.Arbitrary && tx.subtype === TransactionArbitrarySubtype.AliasAssignment) { + item.prefix = '👤'; + item.i18nKey = 'aliasCreation'; + } else if (tx.type === TransactionType.Arbitrary && tx.subtype === TransactionArbitrarySubtype.AliasBuy) { + item.prefix = '👤'; + item.i18nKey = 'aliasSell'; + } else if (tx.type === TransactionType.Arbitrary && tx.subtype === TransactionArbitrarySubtype.AliasSale) { + item.prefix = '👤'; + item.i18nKey = 'aliasBuy'; + } else if (tx.type === TransactionType.Asset && tx.subtype === TransactionAssetSubtype.AssetIssuance) { + item.prefix = '🪙'; + item.i18nKey = 'tokenIssuance'; + // TODO: Adjust SignumJs with new transaction types + } else if (tx.type === TransactionType.Asset && tx.subtype === 6) { + item.prefix = '🪙'; + item.i18nKey = 'tokenMint'; + } else if (tx.type === TransactionType.Asset && tx.subtype === 7) { + item.prefix = '🏦'; + item.i18nKey = 'addTreasuryAccount'; + } + + return item; +} + function isContractCreation(tx: Transaction): boolean { return tx.type === TransactionType.AT && tx.subtype === TransactionSmartContractSubtype.SmartContractCreation; } -export function parseTransaction(tx: Transaction, accountId: string): TransactionItem { - // @ts-ignore - const item: TransactionItem = { +function isContractTransaction(tx: Transaction): boolean { + return tx.senderPublicKey === SMART_CONTRACT_PUBLIC_KEY; +} + +export function parseTransaction(tx: Transaction, accountId: string, accountPrefix: string): TransactionItem { + let item: TransactionItem = { + // @ts-ignore from: tx.senderRS, to: tx.recipientRS || '' }; if (isPayment(tx)) { item.type = tx.sender === accountId ? TransactionItemType.TransferTo : TransactionItemType.TransferFrom; + } else if (isMessage(tx)) { + item.type = tx.sender === accountId ? TransactionItemType.MessageTo : TransactionItemType.MessageFrom; + // @ts-ignore + item.isEncrypted = tx.attachment.encryptedMessage; } else if (isContractCreation(tx)) { item.type = TransactionItemType.Origination; // @ts-ignore - item.contract = Address.fromNumericId(tx.transaction!).getReedSolomonAddress(); + item.contract = Address.fromNumericId(tx.transaction!, accountPrefix).getReedSolomonAddress(); + } else if (isContractTransaction(tx)) { + item.type = TransactionItemType.Interaction; + // @ts-ignore + item.contract = Address.fromNumericId(tx.sender!, accountPrefix).getReedSolomonAddress(); + } else if (isSelfUpdate(tx)) { + item = getSelfUpdateItem(tx); } else { item.type = TransactionItemType.Other; // TODO: name the type more precisely diff --git a/src/lib/temple/activity/types.ts b/src/lib/temple/activity/types.ts index e374f7f..d423df6 100644 --- a/src/lib/temple/activity/types.ts +++ b/src/lib/temple/activity/types.ts @@ -1,39 +1,68 @@ export enum TransactionItemType { TransferTo, TransferFrom, + MessageTo, + MessageFrom, Interaction, Origination, + SelfUpdate, Other } -export type TransactionItem = TransferFromItem | TransferToItem | InteractionItem | OriginationItem | OtherItem; +export type TransactionItem = + | TransferFromItem + | TransferToItem + | MessageToItem + | MessageFromItem + | InteractionItem + | OriginationItem + | SelfUpdateItem + | OtherItem; -export interface OpStackItemBase { +export interface TxItemBase { type: TransactionItemType; } -export interface TransferFromItem extends OpStackItemBase { +export interface TransferFromItem extends TxItemBase { type: TransactionItemType.TransferFrom; from: string; } -export interface TransferToItem extends OpStackItemBase { +export interface TransferToItem extends TxItemBase { type: TransactionItemType.TransferTo; to: string; } -export interface InteractionItem extends OpStackItemBase { +export interface MessageFromItem extends TxItemBase { + type: TransactionItemType.MessageFrom; + from: string; + isEncrypted: boolean; +} + +export interface MessageToItem extends TxItemBase { + type: TransactionItemType.MessageTo; + to: string; + isEncrypted: boolean; +} + +export interface InteractionItem extends TxItemBase { type: TransactionItemType.Interaction; - with: string; - entrypoint: string; + contract: string; } -export interface OriginationItem extends OpStackItemBase { +export interface OriginationItem extends TxItemBase { type: TransactionItemType.Origination; - contract?: string; + contract: string; +} + +export interface SelfUpdateItem extends TxItemBase { + type: TransactionItemType.SelfUpdate; + prefix: string; + i18nKey: string; } -export interface OtherItem extends OpStackItemBase { +export interface OtherItem extends TxItemBase { type: TransactionItemType.Other; + prefix: string; name: string; } diff --git a/src/lib/temple/front/client.ts b/src/lib/temple/front/client.ts index 4eedbe1..0dd65e4 100644 --- a/src/lib/temple/front/client.ts +++ b/src/lib/temple/front/client.ts @@ -20,11 +20,83 @@ type Confirmation = { payload: TempleConfirmationPayload; }; -// FIXME: ping and recreate the client... see how done in contentScript +export const [TempleClientProvider, useTempleClient] = constate(() => { + let intercom = useRef(null); + let unsubscribe = useRef(null); + + const intercomSubscription = (msg: TempleNotification) => { + switch (msg?.type) { + case XTMessageType.StateUpdated: + revalidate(); + break; + + case XTMessageType.ConfirmationRequested: + if (msg.id === confirmationIdRef.current) { + setConfirmation({ id: msg.id, payload: msg.payload }); + } + break; + + case XTMessageType.ConfirmationExpired: + if (msg.id === confirmationIdRef.current) { + resetConfirmation(); + } + break; + } + }; + + const getIntercom = useCallback(() => { + if (!intercom.current) { + unsubscribe.current && unsubscribe.current(); + intercom.current = new IntercomClient(); + unsubscribe.current = intercom.current.subscribe(intercomSubscription); + } + return intercom.current; + }, [intercom, unsubscribe, intercomSubscription]); + + function unsubscribeIntercom() { + unsubscribe.current && unsubscribe.current(); + unsubscribe.current = null; + } -const intercom = new IntercomClient(); + function destroyIntercom() { + intercom.current?.destroy(); + intercom.current = null; + } + + async function getPublicKey(accountPublicKeyHash: string) { + const res = await request({ + type: XTMessageType.RevealPublicKeyRequest, + accountPublicKeyHash + }); + assertResponse(res.type === XTMessageType.RevealPublicKeyResponse); + return res.publicKey; + } + + const request = useCallback(async (req: T): Promise => { + try { + const res = await getIntercom().request(req); + assertResponse('type' in res); + return res as TempleResponse; + } catch (e: any) { + if (e.message === 'Attempting to use a disconnected port object') { + unsubscribeIntercom(); + destroyIntercom(); + + const res = await getIntercom().request(req); + assertResponse('type' in res); + return res as TempleResponse; + } + console.error(e); + throw e; + } + }, []); + + function assertResponse(condition: any): asserts condition { + if (!condition) { + throw new Error('Invalid response received'); + } + } -export const [TempleClientProvider, useTempleClient] = constate(() => { /** * State */ @@ -33,7 +105,7 @@ export const [TempleClientProvider, useTempleClient] = constate(() => { const res = await request({ type: XTMessageType.GetStateRequest }); assertResponse(res.type === XTMessageType.GetStateResponse); return res.state; - }, []); + }, [request]); const { data, revalidate } = useRetryableSWR('state', fetchState, { suspense: true, @@ -51,26 +123,10 @@ export const [TempleClientProvider, useTempleClient] = constate(() => { }, [setConfirmation]); useEffect(() => { - return intercom.subscribe((msg: TempleNotification) => { - switch (msg?.type) { - case XTMessageType.StateUpdated: - revalidate(); - break; - - case XTMessageType.ConfirmationRequested: - if (msg.id === confirmationIdRef.current) { - setConfirmation({ id: msg.id, payload: msg.payload }); - } - break; - - case XTMessageType.ConfirmationExpired: - if (msg.id === confirmationIdRef.current) { - resetConfirmation(); - } - break; - } - }); - }, [revalidate, setConfirmation, resetConfirmation]); + if (!revalidate) return; + getIntercom(); + return unsubscribeIntercom; + }, [revalidate, setConfirmation, resetConfirmation, getIntercom]); /** * Aliases @@ -383,23 +439,23 @@ export const [TempleClientProvider, useTempleClient] = constate(() => { }; }); -async function getPublicKey(accountPublicKeyHash: string) { - const res = await request({ - type: XTMessageType.RevealPublicKeyRequest, - accountPublicKeyHash - }); - assertResponse(res.type === XTMessageType.RevealPublicKeyResponse); - return res.publicKey; -} - -async function request(req: T) { - const res = await intercom.request(req); - assertResponse('type' in res); - return res as TempleResponse; -} - -function assertResponse(condition: any): asserts condition { - if (!condition) { - throw new Error('Invalid response received'); - } -} +// async function getPublicKey(accountPublicKeyHash: string) { +// const res = await request({ +// type: XTMessageType.RevealPublicKeyRequest, +// accountPublicKeyHash +// }); +// assertResponse(res.type === XTMessageType.RevealPublicKeyResponse); +// return res.publicKey; +// } +// +// async function request(req: T) { +// const res = await intercom.request(req); +// assertResponse('type' in res); +// return res as TempleResponse; +// } +// +// function assertResponse(condition: any): asserts condition { +// if (!condition) { +// throw new Error('Invalid response received'); +// } +// } diff --git a/src/lib/temple/metadata/defaults.ts b/src/lib/temple/metadata/defaults.ts index 6aae868..6683352 100644 --- a/src/lib/temple/metadata/defaults.ts +++ b/src/lib/temple/metadata/defaults.ts @@ -25,3 +25,5 @@ export const SIGNA_TESTNET_METADATA: AssetMetadata = { name: 'TSigna', thumbnailUri: browser.runtime.getURL('misc/token-logos/signa.svg') }; + +export const SMART_CONTRACT_PUBLIC_KEY = '0000000000000000000000000000000000000000000000000000000000000000';