From 04830102562349bd120359c536efe4bde8e38897 Mon Sep 17 00:00:00 2001 From: Parv Sharma Date: Mon, 11 Dec 2023 18:27:35 +0530 Subject: [PATCH] refactor & deprecation changes --- .../common-ui/src/models/Cis2Client.ts | 100 +++--- .../src/models/ConcordiumContractClient.ts | 325 +++++++++--------- .../common-ui/src/models/MarketplaceClient.ts | 204 +++++------ 3 files changed, 308 insertions(+), 321 deletions(-) diff --git a/low-code-nft-marketplace/common-ui/src/models/Cis2Client.ts b/low-code-nft-marketplace/common-ui/src/models/Cis2Client.ts index 0d06d7f4..71378287 100644 --- a/low-code-nft-marketplace/common-ui/src/models/Cis2Client.ts +++ b/low-code-nft-marketplace/common-ui/src/models/Cis2Client.ts @@ -1,25 +1,25 @@ import { SmartContractParameters, WalletApi } from "@concordium/browser-wallet-api-helpers"; -import { CIS2, ContractAddress, TransactionSummary } from "@concordium/web-sdk"; +import { BlockItemSummaryInBlock, CIS2, ContractAddress } from '@concordium/web-sdk'; -import * as conClient from "./ConcordiumContractClient"; +import * as conClient from './ConcordiumContractClient'; /** * Structure of a JSON-formatted metadata. */ export interface Metadata { - name?: string; - description?: string; - display?: { - url: string; - }; - unique?: boolean; - attributes?: Attribute[]; + name?: string; + description?: string; + display?: { + url: string; + }; + unique?: boolean; + attributes?: Attribute[]; } export interface Attribute { - name: string; - type: string; - value: string; + name: string; + type: string; + value: string; } /** @@ -31,48 +31,48 @@ export interface Attribute { * @param tokenContractAddress Token contract address. * @param contractInfo Contract info of CIS-2 contract. * @param maxContractExecutionEnergy Max allowed energy ot Minting. - * @returns Transaction outcomes {@link Record} + * @returns Transaction outcomes {@link BlockItemSummaryInBlock} */ export async function mint( - provider: WalletApi, - account: string, - tokens: { [tokenId: string]: [CIS2.MetadataUrl, string] }, - tokenContractAddress: ContractAddress, - contractInfo: conClient.ContractInfo, - maxContractExecutionEnergy = BigInt(9999), -): Promise> { - const paramJson = { - owner: { - Account: [account], - }, - tokens: Object.keys(tokens).map((tokenId) => [ - tokenId, - { - metadata_url: { - url: tokens[tokenId][0].url, - hash: tokens[tokenId][0].hash - ? { - Some: [tokens[tokenId][0].hash!], - } - : { - None: [], - }, + provider: WalletApi, + account: string, + tokens: { [tokenId: string]: [CIS2.MetadataUrl, string] }, + tokenContractAddress: ContractAddress, + contractInfo: conClient.ContractInfo, + maxContractExecutionEnergy = BigInt(9999) +): Promise { + const paramJson = { + owner: { + Account: [account], }, - token_amount: tokens[tokenId][1], - }, - ]), - }; + tokens: Object.keys(tokens).map((tokenId) => [ + tokenId, + { + metadata_url: { + url: tokens[tokenId][0].url, + hash: tokens[tokenId][0].hash + ? { + Some: [tokens[tokenId][0].hash!], + } + : { + None: [], + }, + }, + token_amount: tokens[tokenId][1], + }, + ]), + }; - return conClient.updateContract( - provider, - contractInfo, - paramJson as SmartContractParameters, - account, - tokenContractAddress, - "mint", - maxContractExecutionEnergy, - BigInt(0), - ); + return conClient.updateContract( + provider, + contractInfo, + paramJson as SmartContractParameters, + account, + tokenContractAddress, + 'mint', + maxContractExecutionEnergy, + BigInt(0) + ); } export const toTokenId = (integer: number, contractInfo: conClient.Cis2ContractInfo) => { diff --git a/low-code-nft-marketplace/common-ui/src/models/ConcordiumContractClient.ts b/low-code-nft-marketplace/common-ui/src/models/ConcordiumContractClient.ts index f6a5b6a0..cd0524e6 100644 --- a/low-code-nft-marketplace/common-ui/src/models/ConcordiumContractClient.ts +++ b/low-code-nft-marketplace/common-ui/src/models/ConcordiumContractClient.ts @@ -1,27 +1,29 @@ -import { Buffer } from "buffer/"; +import { Buffer } from 'buffer/'; -import { SmartContractParameters, WalletApi } from "@concordium/browser-wallet-api-helpers"; +import { SmartContractParameters, WalletApi } from '@concordium/browser-wallet-api-helpers'; import { - AccountAddress, - AccountTransactionType, - CcdAmount, - ConcordiumGRPCClient, - ContractAddress, - ModuleReference, - serializeUpdateContractParameters, - TransactionStatusEnum, - TransactionSummary, - UpdateContractPayload, -} from "@concordium/web-sdk"; + AccountAddress, + AccountTransactionType, + BlockItemSummaryInBlock, + CcdAmount, + ConcordiumGRPCClient, + ContractAddress, + ModuleReference, + serializeUpdateContractParameters, + TransactionKindString, + TransactionStatusEnum, + TransactionSummaryType, + UpdateContractPayload, +} from '@concordium/web-sdk'; export interface ContractInfo { - schemaBuffer: Buffer; - contractName: "cis2_multi" | "Market-NFT" | string; - moduleRef?: ModuleReference; + schemaBuffer: Buffer; + contractName: 'cis2_multi' | 'Market-NFT' | string; + moduleRef?: ModuleReference; } export interface Cis2ContractInfo extends ContractInfo { - tokenIdByteSize: number; + tokenIdByteSize: number; } /** @@ -36,34 +38,34 @@ export interface Cis2ContractInfo extends ContractInfo { * @returns Contract Address. */ export async function initContract( - provider: WalletApi, - contractInfo: ContractInfo, - account: string, - params?: SmartContractParameters, - maxContractExecutionEnergy = BigInt(9999), - ccdAmount = BigInt(0), + provider: WalletApi, + contractInfo: ContractInfo, + account: string, + params?: SmartContractParameters, + maxContractExecutionEnergy = BigInt(9999), + ccdAmount = BigInt(0) ): Promise { - const { moduleRef, schemaBuffer, contractName } = contractInfo; - if (!moduleRef) { - throw new Error("Cannot instantiate a Module without Provided Module Ref"); - } + const { moduleRef, schemaBuffer, contractName } = contractInfo; + if (!moduleRef) { + throw new Error('Cannot instantiate a Module without Provided Module Ref'); + } - const txnHash = await provider.sendTransaction( - account, - AccountTransactionType.InitContract, - { - amount: toCcd(ccdAmount), - moduleRef, - initName: contractName, - maxContractExecutionEnergy, - }, - params as SmartContractParameters, - schemaBuffer.toString("base64"), - ); + const txnHash = await provider.sendTransaction( + account, + AccountTransactionType.InitContract, + { + amount: toCcd(ccdAmount), + moduleRef, + initName: contractName, + maxContractExecutionEnergy, + }, + params as SmartContractParameters, + schemaBuffer.toString('base64') + ); - let outcomes = await waitForTransaction(provider, txnHash); - outcomes = ensureValidOutcome(outcomes); - return parseContractAddress(outcomes); + let outcomes = await waitForTransaction(provider, txnHash); + outcomes = ensureValidOutcome(outcomes); + return parseContractAddress(outcomes); } /** @@ -77,40 +79,40 @@ export async function initContract( * @returns Buffer of the return value. */ export async function invokeContract( - grpcClient: ConcordiumGRPCClient, - contractInfo: ContractInfo, - contract: ContractAddress, - methodName: string, - params?: T, - invoker?: ContractAddress | AccountAddress, + grpcClient: ConcordiumGRPCClient, + contractInfo: ContractInfo, + contract: ContractAddress, + methodName: string, + params?: T, + invoker?: ContractAddress | AccountAddress ): Promise { - const { schemaBuffer, contractName } = contractInfo; - const parameter = params ? serializeParams(contractName, schemaBuffer, methodName, params) : undefined; + const { schemaBuffer, contractName } = contractInfo; + const parameter = params ? serializeParams(contractName, schemaBuffer, methodName, params) : undefined; - const res = await grpcClient.invokeContract({ - parameter, - contract, - invoker, - method: `${contractName}.${methodName}`, - }); + const res = await grpcClient.invokeContract({ + parameter, + contract, + invoker, + method: `${contractName}.${methodName}`, + }); - if (!res || res.tag === "failure") { - const msg = - `failed invoking contract ` + - `method:${methodName}, ` + - `contract:(index: ${contract.index.toString()}, subindex: ${contract.subindex.toString()})`; - return Promise.reject(new Error(msg, { cause: res })); - } + if (!res || res.tag === 'failure') { + const msg = + `failed invoking contract ` + + `method:${methodName}, ` + + `contract:(index: ${contract.index.toString()}, subindex: ${contract.subindex.toString()})`; + return Promise.reject(new Error(msg, { cause: res })); + } - if (!res.returnValue) { - const msg = - `failed invoking contract, null return value` + - `method:${methodName}, ` + - `contract:(index: ${contract.index.toString()}, subindex: ${contract.subindex.toString()})`; - return Promise.reject(new Error(msg, { cause: res })); - } + if (!res.returnValue) { + const msg = + `failed invoking contract, null return value` + + `method:${methodName}, ` + + `contract:(index: ${contract.index.toString()}, subindex: ${contract.subindex.toString()})`; + return Promise.reject(new Error(msg, { cause: res })); + } - return Buffer.from(res.returnValue, "hex"); + return Buffer.from(res.returnValue, 'hex'); } /** @@ -127,35 +129,35 @@ export async function invokeContract( * @returns Update contract Outcomes. */ export async function updateContract( - provider: WalletApi, - contractInfo: ContractInfo, - paramJson: SmartContractParameters, - account: string, - contractAddress: ContractAddress, - methodName: string, - maxContractExecutionEnergy = BigInt(9999), - amount = BigInt(0), -): Promise> { - const { schemaBuffer, contractName } = contractInfo; - const txnHash = await provider.sendTransaction( - account, - AccountTransactionType.Update, - { - maxContractExecutionEnergy, - address: contractAddress, - amount: toCcd(amount), - receiveName: `${contractName}.${methodName}`, - } as UpdateContractPayload, - paramJson as any, - schemaBuffer.toString("base64"), - ); + provider: WalletApi, + contractInfo: ContractInfo, + paramJson: SmartContractParameters, + account: string, + contractAddress: ContractAddress, + methodName: string, + maxContractExecutionEnergy = BigInt(9999), + amount = BigInt(0) +): Promise { + const { schemaBuffer, contractName } = contractInfo; + const txnHash = await provider.sendTransaction( + account, + AccountTransactionType.Update, + { + maxContractExecutionEnergy, + address: contractAddress, + amount: toCcd(amount), + receiveName: `${contractName}.${methodName}`, + } as UpdateContractPayload, + paramJson as any, + schemaBuffer.toString('base64') + ); - return await waitAndThrowError(provider, txnHash); + return await waitAndThrowError(provider, txnHash); } export async function waitAndThrowError(provider: WalletApi, txnHash: string) { - const outcomes = await waitForTransaction(provider, txnHash); - return ensureValidOutcome(outcomes); + const outcomes = await waitForTransaction(provider, txnHash); + return ensureValidOutcome(outcomes); } /** @@ -164,34 +166,29 @@ export async function waitAndThrowError(provider: WalletApi, txnHash: string) { * @param txnHash Hash of Transaction. * @returns Transaction outcomes. */ -function waitForTransaction( - provider: WalletApi, - txnHash: string, -): Promise | undefined> { - return new Promise((res, rej) => { - _wait(provider, txnHash, res, rej); - }); +function waitForTransaction(provider: WalletApi, txnHash: string): Promise { + return new Promise((res, rej) => { + _wait(provider, txnHash, res, rej); + }); } -function ensureValidOutcome(outcomes?: Record): Record { - if (!outcomes) { - throw Error("Null Outcome"); - } - - const successTxnSummary = Object.keys(outcomes) - .map((k) => outcomes[k]) - .find((s) => s.result.outcome === "success"); - - if (!successTxnSummary) { - const failures = Object.keys(outcomes) - .map((k) => outcomes[k]) - .filter((s) => s.result.outcome === "reject") - .map((s) => (s.result as any).rejectReason.tag) - .join(","); - throw Error(`Transaction failed, reasons: ${failures}`); - } +function ensureValidOutcome(outcomes?: BlockItemSummaryInBlock): BlockItemSummaryInBlock { + if (!outcomes) { + throw Error('Null Outcome'); + } - return outcomes; + switch (outcomes.summary.type) { + case TransactionSummaryType.UpdateTransaction: + case TransactionSummaryType.AccountCreation: + throw Error(`Invalid Transaction Type: ${outcomes.summary.type}`); + case TransactionSummaryType.AccountTransaction: + switch (outcomes.summary.transactionType) { + case TransactionKindString.Failed: + throw Error(`Transaction failed, reason: ${outcomes.summary.rejectReason.tag}`); + default: + return outcomes; + } + } } /** @@ -203,68 +200,58 @@ function ensureValidOutcome(outcomes?: Record): Reco * @returns Serialize buffer of the input params. */ function serializeParams(contractName: string, schema: Buffer, methodName: string, params: T): Buffer { - return serializeUpdateContractParameters(contractName, methodName, params, schema); + return serializeUpdateContractParameters(contractName, methodName, params, schema); } function _wait( - provider: WalletApi, - txnHash: string, - res: (p: Record | undefined) => void, - rej: (reason: any) => void, + provider: WalletApi, + txnHash: string, + res: (p: BlockItemSummaryInBlock) => void, + rej: (reason: any) => void ) { - setTimeout(() => { - provider - .getJsonRpcClient() - .getTransactionStatus(txnHash) - .then((txnStatus) => { - if (!txnStatus) { - return rej("Transaction Status is null"); - } - - console.info(`txn : ${txnHash}, status: ${txnStatus?.status}`); - if (txnStatus?.status === TransactionStatusEnum.Finalized) { - return res(txnStatus.outcomes); - } - - _wait(provider, txnHash, res, rej); - }) - .catch((err) => rej(err)); - }, 1000); + setTimeout(() => { + provider + .getGrpcClient() + .getBlockItemStatus(txnHash) + .then((status) => { + switch (status.status) { + case TransactionStatusEnum.Received: + case TransactionStatusEnum.Committed: + _wait(provider, txnHash, res, rej); + break; + case TransactionStatusEnum.Finalized: + return res(status.outcome); + } + }) + .catch((err) => rej(err)); + }, 1000); } -function parseContractAddress(outcomes: Record): ContractAddress { - for (const blockHash in outcomes) { - const res = outcomes[blockHash]; - - if (res.result.outcome === "success") { - for (const event of res.result.events) { - if (event.tag === "ContractInitialized") { - return { - index: toBigInt((event as any).address.index), - subindex: toBigInt((event as any).address.subindex), - }; - } - } +function parseContractAddress(outcomes: BlockItemSummaryInBlock): ContractAddress { + switch (outcomes.summary.type) { + case TransactionSummaryType.AccountTransaction: + switch (outcomes.summary.transactionType) { + case TransactionKindString.InitContract: + return outcomes.summary.contractInitialized.address; + default: + throw Error(`Invalid Account Transaction Type: ${outcomes.summary.type}`); + } + break; + default: + throw Error(`Invalid Transaction Type: ${outcomes.summary.type}`); } - } - - throw Error(`unable to parse Contract Address from input outcomes`); -} - -function toBigInt(num: bigint | number): bigint { - return BigInt(num.toString(10)); } const MICRO_CCD_IN_CCD = 1000000; function toCcd(ccdAmount: bigint): CcdAmount { - return new CcdAmount(ccdAmount * BigInt(MICRO_CCD_IN_CCD)); + return new CcdAmount(ccdAmount * BigInt(MICRO_CCD_IN_CCD)); } export function toParamContractAddress(marketAddress: ContractAddress): ParamContractAddress { - return { - index: parseInt(marketAddress.index.toString()), - subindex: parseInt(marketAddress.subindex.toString()), - }; + return { + index: parseInt(marketAddress.index.toString()), + subindex: parseInt(marketAddress.subindex.toString()), + }; } export type ParamContractAddress = { index: number; subindex: number }; diff --git a/low-code-nft-marketplace/common-ui/src/models/MarketplaceClient.ts b/low-code-nft-marketplace/common-ui/src/models/MarketplaceClient.ts index 33d0d136..08355cfe 100644 --- a/low-code-nft-marketplace/common-ui/src/models/MarketplaceClient.ts +++ b/low-code-nft-marketplace/common-ui/src/models/MarketplaceClient.ts @@ -1,23 +1,23 @@ -import { SmartContractParameters, WalletApi } from "@concordium/browser-wallet-api-helpers"; +import { SmartContractParameters, WalletApi } from '@concordium/browser-wallet-api-helpers'; import { - ConcordiumGRPCClient, - ContractAddress, - deserializeReceiveReturnValue, - TransactionSummary, -} from "@concordium/web-sdk"; + BlockItemSummaryInBlock, + ConcordiumGRPCClient, + ContractAddress, + deserializeReceiveReturnValue, +} from '@concordium/web-sdk'; import { - ContractInfo, - invokeContract, - ParamContractAddress, - toParamContractAddress, - updateContract, -} from "./ConcordiumContractClient"; + ContractInfo, + invokeContract, + ParamContractAddress, + toParamContractAddress, + updateContract, +} from './ConcordiumContractClient'; const enum MethodNames { - add = "add", - transfer = "transfer", - list = "list", + add = 'add', + transfer = 'transfer', + list = 'list', } /** @@ -27,32 +27,32 @@ const enum MethodNames { * @returns List of buyable tokens. */ export async function list( - grpcClient: ConcordiumGRPCClient, - marketContractAddress: ContractAddress, - contractInfo: ContractInfo, + grpcClient: ConcordiumGRPCClient, + marketContractAddress: ContractAddress, + contractInfo: ContractInfo ): Promise { - const retValue = await invokeContract(grpcClient, contractInfo, marketContractAddress, MethodNames.list); + const retValue = await invokeContract(grpcClient, contractInfo, marketContractAddress, MethodNames.list); - const retValueDe = deserializeReceiveReturnValue( - retValue, - contractInfo.schemaBuffer, - contractInfo.contractName, - MethodNames.list, - ); + const retValueDe = deserializeReceiveReturnValue( + retValue, + contractInfo.schemaBuffer, + contractInfo.contractName, + MethodNames.list + ); - const tokens = retValueDe[0].map( - (t: any) => - ({ - contract: t.contract, - owner: t.owner, - price: BigInt(t.price), - primaryOwner: t.primary_owner, - quantity: BigInt(t.quantity), - royalty: t.royalty, - tokenId: t.token_id, - } as TokenListItem), - ); - return tokens; + const tokens = retValueDe[0].map( + (t: any) => + ({ + contract: t.contract, + owner: t.owner, + price: BigInt(t.price), + primaryOwner: t.primary_owner, + quantity: BigInt(t.quantity), + royalty: t.royalty, + tokenId: t.token_id, + } as TokenListItem) + ); + return tokens; } /** @@ -65,22 +65,22 @@ export async function list( * @returns Transaction outcomes. */ export async function add( - provider: WalletApi, - account: string, - marketContractAddress: ContractAddress, - paramJson: AddParams, - contractInfo: ContractInfo, - maxContractExecutionEnergy = BigInt(9999), -): Promise> { - return updateContract( - provider, - contractInfo, - paramJson as unknown as SmartContractParameters, - account, - marketContractAddress, - MethodNames.add, - maxContractExecutionEnergy, - ); + provider: WalletApi, + account: string, + marketContractAddress: ContractAddress, + paramJson: AddParams, + contractInfo: ContractInfo, + maxContractExecutionEnergy = BigInt(9999) +): Promise { + return updateContract( + provider, + contractInfo, + paramJson as unknown as SmartContractParameters, + account, + marketContractAddress, + MethodNames.add, + maxContractExecutionEnergy + ); } /** @@ -95,64 +95,64 @@ export async function add( * @returns Transaction outcomes. */ export async function transfer( - provider: WalletApi, - account: string, - marketContractAddress: ContractAddress, - nftContractAddress: ContractAddress, - tokenId: string, - priceCcd: bigint, - owner: string, - quantity: bigint, - contractInfo: ContractInfo, - maxContractExecutionEnergy = BigInt(9999), -): Promise> { - const paramJson: TransferParams = { - cis_contract_address: toParamContractAddress(nftContractAddress), - token_id: tokenId, - to: account, - owner, - quantity: quantity.toString(), - }; + provider: WalletApi, + account: string, + marketContractAddress: ContractAddress, + nftContractAddress: ContractAddress, + tokenId: string, + priceCcd: bigint, + owner: string, + quantity: bigint, + contractInfo: ContractInfo, + maxContractExecutionEnergy = BigInt(9999) +): Promise { + const paramJson: TransferParams = { + cis_contract_address: toParamContractAddress(nftContractAddress), + token_id: tokenId, + to: account, + owner, + quantity: quantity.toString(), + }; - return updateContract( - provider, - contractInfo, - paramJson as unknown as SmartContractParameters, - account, - marketContractAddress, - MethodNames.transfer, - maxContractExecutionEnergy, - priceCcd * quantity, - ); + return updateContract( + provider, + contractInfo, + paramJson as unknown as SmartContractParameters, + account, + marketContractAddress, + MethodNames.transfer, + maxContractExecutionEnergy, + priceCcd * quantity + ); } export type TokenList = TokenListItem[]; export interface TokenListItem { - /** - * Hex of token Id - */ - tokenId: string; - contract: ContractAddress; - price: bigint; - owner: string; - royalty: number; - primaryOwner: string; - quantity: bigint; + /** + * Hex of token Id + */ + tokenId: string; + contract: ContractAddress; + price: bigint; + owner: string; + royalty: number; + primaryOwner: string; + quantity: bigint; } export interface AddParams { - cis_contract_address: ParamContractAddress; - token_id: string; - price: string; - royalty: number; - quantity: string; + cis_contract_address: ParamContractAddress; + token_id: string; + price: string; + royalty: number; + quantity: string; } export interface TransferParams { - cis_contract_address: ParamContractAddress; - token_id: string; - to: string; - owner: string; - quantity: string; + cis_contract_address: ParamContractAddress; + token_id: string; + to: string; + owner: string; + quantity: string; }