From 6e96404110e6dea709b6caabfbd016fa23fd4be1 Mon Sep 17 00:00:00 2001 From: zlayine Date: Fri, 18 Aug 2023 11:08:18 +0300 Subject: [PATCH 1/3] add documentation --- resources/js/components/SideNavbar.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/resources/js/components/SideNavbar.vue b/resources/js/components/SideNavbar.vue index 2680a07..8e5e3fb 100644 --- a/resources/js/components/SideNavbar.vue +++ b/resources/js/components/SideNavbar.vue @@ -17,7 +17,14 @@ -
+
+ + Documentation + Date: Fri, 18 Aug 2023 13:18:10 +0300 Subject: [PATCH 2/3] improve transactions --- resources/js/components/SignTransaction.vue | 27 +++- resources/js/components/Slideover.vue | 7 +- resources/js/components/beam/BeamsList.vue | 4 +- resources/js/components/pages/Collections.vue | 3 +- resources/js/components/pages/FuelTanks.vue | 3 +- resources/js/components/pages/Tokens.vue | 4 +- .../js/components/pages/Transactions.vue | 3 + resources/js/components/pages/Wallets.vue | 3 +- .../common/DetailsTransactionSlideover.vue | 115 ++++++++------ resources/js/factory/transaction.ts | 5 +- resources/js/graphql/query/GetTransaction.ts | 19 ++- resources/js/store/index.ts | 105 +------------ resources/js/store/transaction.ts | 147 ++++++++++++++++++ resources/js/types/types.interface.ts | 4 + 14 files changed, 277 insertions(+), 172 deletions(-) create mode 100644 resources/js/store/transaction.ts diff --git a/resources/js/components/SignTransaction.vue b/resources/js/components/SignTransaction.vue index 75bb26d..748fad0 100644 --- a/resources/js/components/SignTransaction.vue +++ b/resources/js/components/SignTransaction.vue @@ -5,9 +5,10 @@ - Select an account to sign + Select an account to sign the transaction
+
Transaction fee: {{ feeCost }}
{ - useAppStore().getAccounts(); - showAccountsModal.value = true; + try { + if (!appStore.provider) { + snackbar.error({ title: 'Please connect your wallet to sign' }); + return; + } + appStore.getAccounts(); + await transactionStore.init(); + feeCost.value = await transactionStore.getTransactionCost(props.transaction); + showAccountsModal.value = true; + } catch (e) { + console.log(e) + snackbar.error({ title: 'Failed to sign transaction' }); + } }; const closeModal = () => { @@ -58,9 +75,9 @@ const closeModal = () => { const selectAccount = async (account) => { try { isLoading.value = true; - useAppStore().setAccount(account); + appStore.setAccount(account); showAccountsModal.value = false; - const res = await useAppStore().signTransaction(props.transaction); + const res = await transactionStore.signTransaction(props.transaction); if (res) { emit('success'); } diff --git a/resources/js/components/Slideover.vue b/resources/js/components/Slideover.vue index 80fe0c3..4519fe1 100644 --- a/resources/js/components/Slideover.vue +++ b/resources/js/components/Slideover.vue @@ -22,6 +22,10 @@ @close="emit('close')" @update="($event) => emit('update', $event)" /> +
@@ -33,6 +37,7 @@ diff --git a/resources/js/factory/transaction.ts b/resources/js/factory/transaction.ts index d2418b1..92a2336 100644 --- a/resources/js/factory/transaction.ts +++ b/resources/js/factory/transaction.ts @@ -25,9 +25,6 @@ export class DTOTransactionFactory { public static forTransaction(transactionData: any): any { const transaction = transactionData.data.GetTransaction; - return { - items: [DTOTransactionFactory.buildTransaction(transaction)], - cursor: null, - }; + return DTOTransactionFactory.buildTransaction(transaction); } } diff --git a/resources/js/graphql/query/GetTransaction.ts b/resources/js/graphql/query/GetTransaction.ts index 18eb545..22a86bd 100644 --- a/resources/js/graphql/query/GetTransaction.ts +++ b/resources/js/graphql/query/GetTransaction.ts @@ -1,20 +1,29 @@ export default `query GetTransaction($id: BigInt!) { GetTransaction(id: $id) { id - method + wallet { + account { + publicKey + } + } transactionHash + method result state transactionId + encodedData + signedAtBlock events { - edges { + edges { node { - params { + moduleId + eventId + params { type value - } - } + } } + } } } }`; diff --git a/resources/js/store/index.ts b/resources/js/store/index.ts index 2a98761..00f1cce 100644 --- a/resources/js/store/index.ts +++ b/resources/js/store/index.ts @@ -6,72 +6,19 @@ import snackbar from '~/util/snackbar'; import { AuthApi } from '~/api/auth'; import { CollectionApi } from '~/api/collection'; import { WalletConnectModalSign } from '@walletconnect/modal-sign-html'; -import { formatData, snackbarErrors, wcOptions } from '~/util'; +import { wcOptions } from '~/util'; import { wcRequiredNamespaces } from '~/util'; import { getSdkError } from '@walletconnect/utils'; import { PolkadotjsWallet, Wallet } from '@talismn/connect-wallets'; import { ApiPromise, WsProvider } from '@polkadot/api'; import { SignerPayloadJSON } from '@polkadot/types/types'; import { AccountInfoWithTripleRefCount } from '@polkadot/types/interfaces'; -import { TransactionApi } from '~/api/transaction'; -const RPC_URLS = { - canary: 'wss://rpc.matrix.canary.enjin.io', - polkadot: 'wss://rpc.efinity.io', -}; const parseConfigURL = (url: string): URL => { return new URL(url); }; -const updateTransaction = async ({ - id, - transactionHash, - signingAccount, - signedAtBlock, -}: { - id: string; - transactionHash: string; - signingAccount: string; - signedAtBlock: number; -}) => { - try { - const res = await TransactionApi.updateTransaction( - formatData({ - id: id, - transactionHash: transactionHash, - state: 'BROADCAST', - signingAccount: signingAccount, - signedAtBlock: signedAtBlock, - }) - ); - - const updated = res.data?.UpdateTransaction; - - if (updated) { - snackbar.success({ - title: 'Transaction signed', - text: `The transaction was signed successfully`, - }); - - return true; - } - - snackbar.error({ - title: 'Sign Transaction', - text: 'Signing transaction failed', - }); - - return false; - } catch (e) { - if (snackbarErrors(e)) return; - snackbar.error({ - title: 'Sign Transaction', - text: 'Signing transaction failed', - }); - } -}; - export const useAppStore = defineStore('app', { state: (): AppState => ({ url: undefined, @@ -340,55 +287,7 @@ export const useAppStore = defineStore('app', { this.provider = 'polkadot.js'; } }, - async signTransaction(transaction: any) { - const provider = new WsProvider(RPC_URLS[this.config.network]); - const api = await ApiPromise.create({ provider }); - const [genesisHash, currentBlock, runtime, account] = await Promise.all([ - api.rpc.chain.getBlockHash(0), - api.rpc.chain.getBlock(), - api.rpc.state.getRuntimeVersion(), - // @ts-ignore - api.query.system.account(this.account.address), - ]); - - // This is the call that comes from the platform transactions 'encodedCall' - const call = transaction.encodedData; - const era = '00'; // 00 is for immortal transactions - const genesis = genesisHash.toHex(); // The genesis block - const blockHash = genesisHash.toHex(); // For immortal transactions the blockhash needs to be the genesis - - const payloadToSign: SignerPayloadJSON = { - specVersion: runtime.specVersion.toString(), - transactionVersion: runtime.transactionVersion.toString(), - address: this.account.address, - blockHash: blockHash, - blockNumber: '0x00', - era: '0x' + era, - genesisHash: genesis, - method: call, - nonce: account.nonce.toHex(), - signedExtensions: api.registry.signedExtensions, - tip: '0x00', - version: 4, - }; - - const { signature } = await this.account.signer.signPayload(payloadToSign); - - const extrinsic = api.registry.createType( - 'Extrinsic', - { method: payloadToSign.method }, - { version: payloadToSign.version } - ); - extrinsic.addSignature(this.account.address, signature, payloadToSign); - - const transactionHash = await api.rpc.author.submitExtrinsic(extrinsic.toHex()); - return await updateTransaction({ - id: transaction.id, - transactionHash: transactionHash.toHex(), - signingAccount: this.account.address, - signedAtBlock: currentBlock.block.header.number.toNumber(), - }); - }, + async disconnectWallet() { try { if (this.provider === 'wc') { diff --git a/resources/js/store/transaction.ts b/resources/js/store/transaction.ts new file mode 100644 index 0000000..904dfcf --- /dev/null +++ b/resources/js/store/transaction.ts @@ -0,0 +1,147 @@ +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { defineStore } from 'pinia'; +import { TransactionState } from '~/types/types.interface'; +import { useAppStore } from '.'; +import { TransactionApi } from '~/api/transaction'; +import { formatData, snackbarErrors } from '~/util'; +import snackbar from '~/util/snackbar'; +import { SignerPayloadJSON } from '@polkadot/types/types'; + +const RPC_URLS = { + canary: 'wss://rpc.matrix.canary.enjin.io', + polkadot: 'wss://rpc.efinity.io', +}; + +export const useTransactionStore = defineStore('transaction', { + state: (): TransactionState => ({ + api: null, + }), + actions: { + async init() { + const provider = new WsProvider(RPC_URLS[useAppStore().config.network]); + const api = await ApiPromise.create({ provider }); + console.log(api) + }, + async getExtrinsicData(transaction: any, address: string) { + console.log('here'); + console.log(address); + const [genesisHash, currentBlock, runtime, account] = await Promise.all([ + this.api.rpc.chain.getBlockHash(0), + this.api.rpc.chain.getBlock(), + this.api.rpc.state.getRuntimeVersion(), + // @ts-ignore + this.api.query.system.account(address), + ]); + + // This is the call that comes from the platform transactions 'encodedCall' + const call = transaction.encodedData; + const era = '00'; // 00 is for immortal transactions + const genesis = genesisHash.toHex(); // The genesis block + const blockHash = genesisHash.toHex(); // For immortal transactions the blockhash needs to be the genesis + + const payloadToSign: SignerPayloadJSON = { + specVersion: runtime.specVersion.toString(), + transactionVersion: runtime.transactionVersion.toString(), + address: address, + blockHash: blockHash, + blockNumber: '0x00', + era: '0x' + era, + genesisHash: genesis, + method: call, + nonce: account.nonce.toHex(), + signedExtensions: this.api.registry.signedExtensions, + tip: '0x00', + version: 4, + }; + + const extrinsic = this.api.registry.createType( + 'Extrinsic', + { method: payloadToSign.method }, + { version: payloadToSign.version } + ); + + return { + extrinsic, + payloadToSign, + currentBlock, + }; + }, + async getTransactionCost(transaction: any) { + const { extrinsic } = await this.getExtrinsicData(transaction, useAppStore().accounts[0].address); + console.log('here 1'); + + const paymentInfo = await this.api.tx[extrinsic.method.section] + [extrinsic.method.method](...extrinsic.method.args) + .paymentInfo(useAppStore().accounts[0].address); + + console.log('here 2'); + return paymentInfo.partialFee.toHuman(); + }, + async signTransaction(transaction: any) { + const { extrinsic, payloadToSign, currentBlock } = await this.getExtrinsicData( + transaction, + useAppStore().account.address + ); + + const { signature } = await useAppStore().account.signer.signPayload(payloadToSign); + + extrinsic.addSignature(useAppStore().account.address, signature, payloadToSign); + + const transactionHash = await this.api.rpc.author.submitExtrinsic(extrinsic.toHex()); + + return await this.updateTransaction({ + id: transaction.id, + transactionHash: transactionHash.toHex(), + signingAccount: useAppStore().account.address, + signedAtBlock: currentBlock.block.header.number.toNumber(), + }); + }, + async updateTransaction({ + id, + transactionHash, + signingAccount, + signedAtBlock, + }: { + id: string; + transactionHash: string; + signingAccount: string; + signedAtBlock: number; + }) { + try { + const res = await TransactionApi.updateTransaction( + formatData({ + id: id, + transactionHash: transactionHash, + state: 'BROADCAST', + signingAccount: signingAccount, + signedAtBlock: signedAtBlock, + }) + ); + + const updated = res.data?.UpdateTransaction; + + if (updated) { + snackbar.success({ + title: 'Transaction signed', + text: `The transaction was signed successfully`, + }); + + return true; + } + + snackbar.error({ + title: 'Sign Transaction', + text: 'Signing transaction failed', + }); + + return false; + } catch (e) { + if (snackbarErrors(e)) return; + snackbar.error({ + title: 'Sign Transaction', + text: 'Signing transaction failed', + }); + } + }, + }, +}); diff --git a/resources/js/types/types.interface.ts b/resources/js/types/types.interface.ts index e05cc80..38ea4a8 100644 --- a/resources/js/types/types.interface.ts +++ b/resources/js/types/types.interface.ts @@ -25,6 +25,10 @@ export interface AppState { accounts: any; } +export interface TransactionState { + api: any; +} + export interface NotificationsState { notifications: NotificationInfo[]; } From 743bee1e23242206764d7a45844d92d76b5c84c7 Mon Sep 17 00:00:00 2001 From: zlayine Date: Fri, 18 Aug 2023 14:20:28 +0300 Subject: [PATCH 3/3] fix transaction --- resources/js/components/SignTransaction.vue | 52 +++++++++++++------ .../common/DetailsTransactionSlideover.vue | 6 ++- resources/js/store/index.ts | 10 ++-- resources/js/store/transaction.ts | 32 ++++++------ 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/resources/js/components/SignTransaction.vue b/resources/js/components/SignTransaction.vue index 748fad0..8c42fcb 100644 --- a/resources/js/components/SignTransaction.vue +++ b/resources/js/components/SignTransaction.vue @@ -7,20 +7,34 @@ Select an account to sign the transaction -
-
Transaction fee: {{ feeCost }}
-
- -
- {{ account.name }} - - {{ addressShortHex(account.address) }} - +
+
+ Transaction fee: + + + {{ feeCost }} + +
+
+ +
+
+
+ +
+ {{ account.name }} + + {{ addressShortHex(account.address) }} + +
+
+
+ No accounts found. Please connect your wallet.
@@ -47,7 +61,8 @@ const emit = defineEmits(['success']); const isLoading = ref(false); const showAccountsModal = ref(false); -const feeCost = ref(0); +const feeCost = ref(); +const loadingApi = ref(false); const appStore = useAppStore(); const transactionStore = useTransactionStore(); @@ -56,15 +71,18 @@ const signTransaction = async () => { try { if (!appStore.provider) { snackbar.error({ title: 'Please connect your wallet to sign' }); + return; } + showAccountsModal.value = true; + loadingApi.value = true; appStore.getAccounts(); await transactionStore.init(); feeCost.value = await transactionStore.getTransactionCost(props.transaction); - showAccountsModal.value = true; + loadingApi.value = false; } catch (e) { - console.log(e) snackbar.error({ title: 'Failed to sign transaction' }); + loadingApi.value = false; } }; diff --git a/resources/js/components/slideovers/common/DetailsTransactionSlideover.vue b/resources/js/components/slideovers/common/DetailsTransactionSlideover.vue index 0a96fb9..f53326b 100644 --- a/resources/js/components/slideovers/common/DetailsTransactionSlideover.vue +++ b/resources/js/components/slideovers/common/DetailsTransactionSlideover.vue @@ -172,6 +172,11 @@ const isAddressKey = (key) => ['who', 'operator', 'account', 'owner'].includes(k const getTransaction = async () => { try { + if (props.item?.state === TransactionState.FINALIZED) { + transaction.value = props.item; + return; + } + isLoading.value = true; const res = await TransactionApi.getTransaction(props.item?.id ?? ''); transaction.value = DTOTransactionFactory.forTransaction(res); @@ -179,7 +184,6 @@ const getTransaction = async () => { emit('update', transaction.value); } } catch (error) { - console.log(error); // Do notihing } isLoading.value = false; diff --git a/resources/js/store/index.ts b/resources/js/store/index.ts index 00f1cce..8c72a31 100644 --- a/resources/js/store/index.ts +++ b/resources/js/store/index.ts @@ -10,10 +10,6 @@ import { wcOptions } from '~/util'; import { wcRequiredNamespaces } from '~/util'; import { getSdkError } from '@walletconnect/utils'; import { PolkadotjsWallet, Wallet } from '@talismn/connect-wallets'; -import { ApiPromise, WsProvider } from '@polkadot/api'; -import { SignerPayloadJSON } from '@polkadot/types/types'; -import { AccountInfoWithTripleRefCount } from '@polkadot/types/interfaces'; - const parseConfigURL = (url: string): URL => { return new URL(url); @@ -79,6 +75,10 @@ export const useAppStore = defineStore('app', { if (this.isMultiTenant && this.loggedIn) await this.getUser(); + if (!this.isMultiTenant && this.config.url && this.config.authorization_token) { + this.loggedIn = true; + } + return await this.fetchCollectionIds(); } catch (error: any) { snackbar.error({ title: error }); @@ -287,7 +287,7 @@ export const useAppStore = defineStore('app', { this.provider = 'polkadot.js'; } }, - + async disconnectWallet() { try { if (this.provider === 'wc') { diff --git a/resources/js/store/transaction.ts b/resources/js/store/transaction.ts index 904dfcf..5c891ae 100644 --- a/resources/js/store/transaction.ts +++ b/resources/js/store/transaction.ts @@ -6,6 +6,8 @@ import { TransactionApi } from '~/api/transaction'; import { formatData, snackbarErrors } from '~/util'; import snackbar from '~/util/snackbar'; import { SignerPayloadJSON } from '@polkadot/types/types'; +import { markRaw } from 'vue'; +import { AccountInfoWithTripleRefCount } from '@polkadot/types/interfaces'; const RPC_URLS = { canary: 'wss://rpc.matrix.canary.enjin.io', @@ -18,19 +20,20 @@ export const useTransactionStore = defineStore('transaction', { }), actions: { async init() { + if (this.api) { + return; + } + const provider = new WsProvider(RPC_URLS[useAppStore().config.network]); const api = await ApiPromise.create({ provider }); - console.log(api) + this.api = markRaw(api); }, - async getExtrinsicData(transaction: any, address: string) { - console.log('here'); - console.log(address); + async getExtrinsicData(transaction: any, address: string, api: any) { const [genesisHash, currentBlock, runtime, account] = await Promise.all([ - this.api.rpc.chain.getBlockHash(0), - this.api.rpc.chain.getBlock(), - this.api.rpc.state.getRuntimeVersion(), - // @ts-ignore - this.api.query.system.account(address), + api.rpc.chain.getBlockHash(0), + api.rpc.chain.getBlock(), + api.rpc.state.getRuntimeVersion(), + api.query.system.account(address), ]); // This is the call that comes from the platform transactions 'encodedCall' @@ -49,12 +52,12 @@ export const useTransactionStore = defineStore('transaction', { genesisHash: genesis, method: call, nonce: account.nonce.toHex(), - signedExtensions: this.api.registry.signedExtensions, + signedExtensions: api.registry.signedExtensions, tip: '0x00', version: 4, }; - const extrinsic = this.api.registry.createType( + const extrinsic = api.registry.createType( 'Extrinsic', { method: payloadToSign.method }, { version: payloadToSign.version } @@ -67,20 +70,19 @@ export const useTransactionStore = defineStore('transaction', { }; }, async getTransactionCost(transaction: any) { - const { extrinsic } = await this.getExtrinsicData(transaction, useAppStore().accounts[0].address); - console.log('here 1'); + const { extrinsic } = await this.getExtrinsicData(transaction, useAppStore().accounts[0].address, this.api); const paymentInfo = await this.api.tx[extrinsic.method.section] [extrinsic.method.method](...extrinsic.method.args) .paymentInfo(useAppStore().accounts[0].address); - console.log('here 2'); return paymentInfo.partialFee.toHuman(); }, async signTransaction(transaction: any) { const { extrinsic, payloadToSign, currentBlock } = await this.getExtrinsicData( transaction, - useAppStore().account.address + useAppStore().account.address, + this.api ); const { signature } = await useAppStore().account.signer.signPayload(payloadToSign);