From d42e09a4f5a279d7a8cb4ef7134590cdf9318e9b Mon Sep 17 00:00:00 2001 From: William Chong Date: Fri, 1 Apr 2022 01:08:36 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Support=20update=20ISCN=20in=20iscn?= =?UTF-8?q?-ar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/in/widget/iscn-ar/index.vue | 41 +++++++++++++++++++++++++++---- store/modules/actions/payment.js | 3 ++- util/ValidationHelper.js | 4 +++ util/cosmos/iscn/query.js | 25 +++++++++++++++++-- util/cosmos/iscn/sign.js | 9 +++++-- 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/pages/in/widget/iscn-ar/index.vue b/pages/in/widget/iscn-ar/index.vue index 9d8611a5d..9eedb55a9 100644 --- a/pages/in/widget/iscn-ar/index.vue +++ b/pages/in/widget/iscn-ar/index.vue @@ -324,6 +324,7 @@ import BigNumber from 'bignumber.js'; import mime from 'mime-types'; import { timeout } from '@/util/misc'; import { checkIsMobileClient } from '~/util/client'; +import { checkISCNIdValid } from '~/util/ValidationHelper'; import { queryLikeCoinBalance as queryCosmosLikeCoinBalance, calculateGas as calculateCosmosGas, @@ -333,7 +334,7 @@ import { apiArweaveUpload, } from '@/util/api/api'; import Keplr from '@/util/Keplr'; -import { getISCNTransferInfo } from '@/util/cosmos/iscn/query'; +import { getISCNTransferInfo, getISCNInfoById } from '@/util/cosmos/iscn/query'; import { ISCN_LICENSES, ISCN_PUBLISHERS } from '@/util/cosmos/iscn/constant'; import { IS_TESTNET, STUB_WALLET } from '@/constant'; import ArrowRightNewIcon from '@/assets/icons/arrow-right-new.svg'; @@ -355,7 +356,8 @@ export default { arweaveGasFee: '', arweavePaymentInfo: null, arweaveResult: null, - redirectUri: this.$route.query.redirectUri, + iscnId: this.$route.query.iscn_id, + redirectUri: this.$route.query.redirect_uri, opener: this.$route.query.opener && this.$route.query.opener !== '0', isUsingKeplr: false, mainStatus: 'initial', @@ -368,6 +370,7 @@ export default { LedgerIcon, StarIcon, isMobileClient: false, + existingISCNInfo: null, }; }, async asyncData({ @@ -376,11 +379,13 @@ export default { const { redirect_uri: redirectUri, opener, + iscn_id: iscnId, } = query; const hasOpener = opener && opener !== '0'; return { redirectUri, opener: hasOpener, + iscnId, }; }, head() { @@ -404,6 +409,9 @@ export default { if (!window) return null; return window.opener; }, + isUpdateMode() { + return !!this.iscnId; + }, iscnName() { return (this.ISCNData && this.ISCNData.name); }, @@ -415,6 +423,9 @@ export default { } return f; }, + existingOwner() { + return this.existingISCNInfo && this.existingISCNInfo.owner; + }, showKeplrOverrideButton() { return this.showWalletOption && (this.isMobileClient || this.getUserIsRegistered) @@ -422,9 +433,26 @@ export default { }, }, async mounted() { - this.isMobileClient = checkIsMobileClient(); if (this.opener && !window.opener) { this.$nuxt.error({ statusCode: 400, message: 'Cannot access window opener' }); + return; + } + this.isMobileClient = checkIsMobileClient(); + if (this.iscnId) { + if (!checkISCNIdValid(this.iscnId)) { + this.$nuxt.error({ statusCode: 400, message: 'Invalid ISCN ID' }); + return; + } + try { + this.isLoading = true; + this.existingISCNInfo = await getISCNInfoById(this.iscnId); + } catch (err) { + console.error(err); + this.$nuxt.error({ statusCode: 400, message: 'Error fetching ISCN ID Info' }); + return; + } finally { + this.isLoading = false; + } } window.addEventListener( 'message', @@ -660,8 +688,8 @@ export default { license, url, signer, - shouldShowTxDialog: false, - }); + iscnId: this.iscnId, + }, { update: true }); this.transactionStatus = 'done'; this.mainStatus = 'uploading'; if (txHash) { @@ -775,6 +803,9 @@ export default { throw new Error('VALIDATION_FAIL'); } } + if (this.isUpdateMode && this.existingOwner !== from) { + throw new Error('NOT_OWNER_OF_ISCN'); + } const balance = await queryCosmosLikeCoinBalance(from); if (amount.gt(balance)) { throw new Error('INSUFFICIENT_BALANCE'); diff --git a/store/modules/actions/payment.js b/store/modules/actions/payment.js index 57f05b25e..dc765a293 100644 --- a/store/modules/actions/payment.js +++ b/store/modules/actions/payment.js @@ -119,6 +119,7 @@ export async function calculateISCNTxTotalFee({ commit }, export async function sendISCNSignature( { commit }, { + iscnId = '', isWait = true, showDialogAction = true, signer, @@ -155,7 +156,7 @@ export async function sendISCNSignature( authorDescription, description, cosmosWallet, - }, signer, cosmosWallet, { memo, broadcast: false }); + }, signer, cosmosWallet, { iscnId, memo, broadcast: false }); if (!txRaw) { throw new Error('TX_SIGN_FAILED_UNKNOWN'); } commit(types.UI_SET_SIGN_FINISH, true); const { txHash, included } = await broadcastCosmos(txRaw); diff --git a/util/ValidationHelper.js b/util/ValidationHelper.js index a128ddd13..da8d8746d 100644 --- a/util/ValidationHelper.js +++ b/util/ValidationHelper.js @@ -7,6 +7,10 @@ export function checkUserNameValid(user) { return user && (/^[a-z0-9-_]+$/.test(user) && user.length >= MIN_USER_ID_LENGTH && user.length <= MAX_USER_ID_LENGTH); } +export function checkISCNIdValid(id) { + return /^iscn:\/\/likecoin-chain\/[-_.:=+,a-zA-Z0-9]+(?:\/([0-9]+))?$/.test(id); +} + export function isValidHttpUrl(string) { let url; diff --git a/util/cosmos/iscn/query.js b/util/cosmos/iscn/query.js index f4dddd696..6dd6da409 100644 --- a/util/cosmos/iscn/query.js +++ b/util/cosmos/iscn/query.js @@ -13,6 +13,12 @@ export async function getApiClient() { return stargateClient; } +export async function getISCNQueryClient() { + const queryClient = new ISCNQueryClient(); + await queryClient.connect(ISCN_RPC_URL); + return queryClient; +} + export async function getISCNTransferInfo(txHash, opt) { const apiClient = await getApiClient(); const { blocking } = opt; @@ -65,8 +71,7 @@ export async function getISCNTransferInfo(txHash, opt) { }); }); const [message] = messages; - const queryClient = new ISCNQueryClient(); - await queryClient.connect(ISCN_RPC_URL); + const queryClient = await getISCNQueryClient(); const res = await queryClient.queryRecordsById(message.id); if (!res) throw Error('Error occured when querying ISCN record.'); const iscnVersion = res.records[0].data.recordVersion; @@ -111,6 +116,22 @@ export async function getISCNTransferInfo(txHash, opt) { }; } +export async function getISCNInfoById(iscnId) { + const queryClient = await getISCNQueryClient(); + const { + owner, latestVersion, records, ...other + } = await queryClient.queryRecordsById(iscnId); + const targetVersion = Number(latestVersion); + const record = records.find(r => r.data.recordVersion === targetVersion); + return { + ...other, + owner, + latestVersion, + records, + record, + }; +} + export async function getISCNTransactionCompleted(txHash) { const apiClient = await getApiClient(); const txData = await apiClient.getTx(txHash); diff --git a/util/cosmos/iscn/sign.js b/util/cosmos/iscn/sign.js index 74d27d640..9dc606d0b 100644 --- a/util/cosmos/iscn/sign.js +++ b/util/cosmos/iscn/sign.js @@ -160,9 +160,14 @@ export async function calculateISCNTotalFee(tx) { return { ISCNTotalFee }; } -export async function signISCNTx(tx, signer, address, { memo, broadcast = true } = {}) { +export async function signISCNTx(tx, signer, address, { iscnId, memo, broadcast = true } = {}) { const payload = preformatISCNPayload(tx); const client = await getISCNSigningClient(signer); - const res = await client.createISCNRecord(address, payload, { memo, broadcast }); + let res; + if (iscnId) { + res = await client.updateISCNRecord(address, iscnId, payload, { memo, broadcast }); + } else { + res = await client.createISCNRecord(address, payload, { memo, broadcast }); + } return res; }