Calling nft methods from web

I implemented the frontend as explained in Setting up the front end — Concordium documentation however, still i cannot transfer, the transfer code is

const tokenId = ‘00000003’; // HEX string representing a token ID defined in the contract.
const from = ‘3SfHLNkmy61ZUQkAhMvAwKj47EYDBiUPbn3wHghFD6qGr8WDGc’;
const to = ‘4GyTSko7UZ9iTeUHSLD2c4f3KR6C2nRyyNWbrFMWyC7rRLWDE9’; // An account receiver.
// const to = {address: {index: 1234n, subindex: 0n}, hookName: ‘someReceiveHookName’} // A contract receiver can be specified as such.
const tokenAmount = 1n;
const contractAddressT = ContractAddress.create(8665n, 0n);
const contract = await CIS2Contract.create(client, contractAddressT);

const transfer =     {
  tokenId: tokenId,
  to: to,
  from: from,
  tokenAmount: tokenAmount,

}
// const transfer [{ from, to, tokenAmount, tokenId }, { from, to, tokenAmount, tokenId }] // Example of batch update.

const {
  type:t1, // The transaction type.
  payload, // The transaction payload
  parameter: {
      json, // The parameter to be supplied to the contract receive function in JSON format.
      hex, // The parameter to be supplied to the contract receive function as a hex encoded string
  },
  schema: {
      value, // The contract schema for the parameter. This is needed to translate the JSON format to a byte array.
      type:t2, // The type of the schema. This is always 'parameter', meaning it can be used for the JSON formatted parameter only.
  }

} = contract.createTransfer(
{ energy: Energy.create(1000000) },
{
tokenId: ‘00000003’,
to: AccountAddress.fromBase58(
‘4GyTSko7UZ9iTeUHSLD2c4f3KR6C2nRyyNWbrFMWyC7rRLWDE9’
),
from: AccountAddress.fromBase58(
‘3SfHLNkmy61ZUQkAhMvAwKj47EYDBiUPbn3wHghFD6qGr8WDGc’
),
tokenAmount: 1n,
}
);
console.log(t1)
console.log(payload)
// console.log(parameter)

for browser wallet connection following is used

import {
useGrpcClient,
WalletConnectionProps,
useConnect,
useConnection,
BrowserWalletConnector,
} from ‘@concordium/react-components’;

Wallet is connected but I am never prompted for a transaction which is created above, so what am I missing

The code snippet you pasted related to wallet connection does not actually manage any connection to any wallet though; it just imports stuff from the library used to maintain connections?

If you want to use @concordium/react-components to manage connections to compatible wallets, I would encourage you to take a look at the documentation for the library at concordium-dapp-libraries/packages/react-components at main · Concordium/concordium-dapp-libraries · GitHub

The repository includes example implementations as well, the simplest of them can be checked out here: concordium-dapp-libraries/samples/sign-message at main · Concordium/concordium-dapp-libraries · GitHub

my goal is to just have a transfer to occur on a button click, the simplest possible way from frontend

I would still take a look at the example I linked in the previous reply as that exemplifies the following flow:

  • Allow user to connect to application
  • Interact with the API of the wallet connection, i.e. sign a message in the wallet (or in your case send a transaction).

Thx, that helped, please see the screen shots



The transaction is following
https://testnet.ccdscan.io/?dcount=1&dentity=transaction&dhash=a6377dcd64868fedc9c74ee04c9f8930317c0085ff51f505dc49126cff4bd172

It is rejected, what is causing the rejection?

This error means nonPayable. Meaning you send CCD to the smart contract endpoint but the endpoint is nonPayable. You can change the CCD amount to 0 when sending the transaction (not the amount in the input parameter).

Thx, I get CCDScan

You can read up about the error codes here:
https://developer.concordium.software/en/mainnet/smart-contracts/tutorials/piggy-bank/deploying.html#smart-contract-errors

-1 often means that the smart contract can not parse your input parameter.

The issue is that contract expects an array as input however, the sample does not allow to, so I decided to port required code into separate project and intended to use browserwallet, however, I get following error.

@concordium_react-components.js?v=861a4795:13053 Uncaught TypeError: setActiveConnectorType is not a function
at @concordium_react-components.js?v=861a4795:13053:55
at HTMLUnknownElement.callCallback2 (chunk-NTZW7WAF.js?v=861a4795:3674:22)
at Object.invokeGuardedCallbackDev (chunk-NTZW7WAF.js?v=861a4795:3699:24)
at invokeGuardedCallback (chunk-NTZW7WAF.js?v=861a4795:3733:39)
at invokeGuardedCallbackAndCatchFirstError (chunk-NTZW7WAF.js?v=861a4795:3736:33)
at executeDispatch (chunk-NTZW7WAF.js?v=861a4795:7016:11)
at processDispatchQueueItemsInOrder (chunk-NTZW7WAF.js?v=861a4795:7036:15)
at processDispatchQueue (chunk-NTZW7WAF.js?v=861a4795:7045:13)
at dispatchEventsForPlugins (chunk-NTZW7WAF.js?v=861a4795:7053:11)
at chunk-NTZW7WAF.js?v=861a4795:7177:20

Relevant Code

import React from ‘react’;
import { Button } from ‘react-bootstrap’;
import {
ConnectorType,
WalletConnection,
WalletConnectionProps,
useWalletConnectorSelector,
} from ‘@concordium/react-components’;

interface Props extends WalletConnectionProps {
connection: WalletConnection | undefined;
connectorType: ConnectorType;
connectorName: string;
}

export function WalletConnectorButton(props: Props) {
const { connection, connectorType, connectorName } = props;
const { isSelected, isConnected, isDisabled, select } = useWalletConnectorSelector(
connectorType,
connection,
props
);

const verb = isConnected ? 'Disconnect' : isSelected ? 'Using' : 'Use';
return (
    <Button
        className="w-100"
        disabled={isDisabled}
        variant={isConnected ? 'danger' : isSelected ? 'dark' : 'light'}
        onClick={select}
    >
        {`${verb} ${connectorName}`}
    </Button>
);

}

Here is an example how to use the hook:

Thx, I get following error

chunk-NTZW7WAF.js?v=861a4795:9145 Uncaught TypeError: setActiveConnectorType is not a function
at App.tsx:129:5
at commitHookEffectListMount (chunk-NTZW7WAF.js?v=861a4795:16936:34)
at commitPassiveMountOnFiber (chunk-NTZW7WAF.js?v=861a4795:18184:19)
at commitPassiveMountEffects_complete (chunk-NTZW7WAF.js?v=861a4795:18157:17)
at commitPassiveMountEffects_begin (chunk-NTZW7WAF.js?v=861a4795:18147:15)
at commitPassiveMountEffects (chunk-NTZW7WAF.js?v=861a4795:18137:11)
at flushPassiveEffectsImpl (chunk-NTZW7WAF.js?v=861a4795:19518:11)
at flushPassiveEffects (chunk-NTZW7WAF.js?v=861a4795:19475:22)
at chunk-NTZW7WAF.js?v=861a4795:19356:17
at workLoop (chunk-NTZW7WAF.js?v=861a4795:197:42)

Code for App.tsx

import { useEffect, useState } from ‘react’
import reactLogo from ‘./assets/react.svg’
import viteLogo from ‘/vite.svg’
import { parseEndpoint } from ‘./shared/util’;
import { credentials } from ‘@grpc/grpc-js’;

import ‘./App.css’
// import { ConcordiumGRPCWebClient, ContractAddress } from ‘@concordium/web-sdk’;
import {
AccountAddress,
BlockHash,
CcdAmount,
ContractAddress,
ContractContext,
ContractTraceEvent,
Energy,
Parameter,
ReceiveName,
ReturnValue,
ConcordiumGRPCWebClient,
CIS2Contract,
} from ‘@concordium/web-sdk’;
import { WalletConnectorButton } from ‘./WalletConnectorButton’;

import { Network, WalletConnection } from ‘@concordium/react-components’;
import { MAINNET, TESTNET, WalletConnectionProps, WithWalletConnector,ephemeralConnectorType, BrowserWalletConnector} from ‘@concordium/react-components’;
import { useConnect, useConnection, useGrpcClient } from ‘@concordium/react-components’;
// import { BROWSER_WALLET, WALLET_CONNECT } from ‘./config’;

const BROWSER_WALLET = ephemeralConnectorType(BrowserWalletConnector.create);

// import meow from ‘meow’;

const address =‘http://node.testnet.concordium.com
const port = Number(20000)

// const [address, port] = parseEndpoint(cli.flags.endpoint);

const client = new ConcordiumGRPCWebClient(
address,
port,
{ timeout: 15000 }
);
console.log(client)

function App(props: WalletConnectionProps) {
const [count, setCount] = useState(0)

const { activeConnectorType, setActiveConnectorType, activeConnector, activeConnectorError, network, connectedAccounts, genesisHashes } =
props;
const { connection, setConnection, account, genesisHash } = useConnection(connectedAccounts, genesisHashes);
const { connect, isConnecting, connectError } = useConnect(activeConnector, setConnection);
function callMint() {

}

async function connectWallet() {

}

async function transferTokens() {
const tokenId = ‘00000003’; // HEX string representing a token ID defined in the contract.
const from = ‘3SfHLNkmy61ZUQkAhMvAwKj47EYDBiUPbn3wHghFD6qGr8WDGc’;
const to = ‘4GyTSko7UZ9iTeUHSLD2c4f3KR6C2nRyyNWbrFMWyC7rRLWDE9’; // An account receiver.
// const to = {address: {index: 1234n, subindex: 0n}, hookName: ‘someReceiveHookName’} // A contract receiver can be specified as such.
const tokenAmount = 1n;
const contractAddressT = ContractAddress.create(8665n, 0n);
const contract = await CIS2Contract.create(client, contractAddressT);

const transfer =     {
  tokenId: tokenId,
  to: to,
  from: from,
  tokenAmount: tokenAmount,

}
// const transfer [{ from, to, tokenAmount, tokenId }, { from, to, tokenAmount, tokenId }] // Example of batch update.

const {
  type:t1, // The transaction type.
  payload, // The transaction payload
  parameter: {
      json, // The parameter to be supplied to the contract receive function in JSON format.
      hex, // The parameter to be supplied to the contract receive function as a hex encoded string
  },
  schema: {
      value, // The contract schema for the parameter. This is needed to translate the JSON format to a byte array.
      type:t2, // The type of the schema. This is always 'parameter', meaning it can be used for the JSON formatted parameter only.
  }

} = contract.createTransfer(
{ energy: Energy.create(1000000) },
{
tokenId: ‘00000003’,
to: AccountAddress.fromBase58(
‘4GyTSko7UZ9iTeUHSLD2c4f3KR6C2nRyyNWbrFMWyC7rRLWDE9’
),
from: AccountAddress.fromBase58(
‘3SfHLNkmy61ZUQkAhMvAwKj47EYDBiUPbn3wHghFD6qGr8WDGc’
),
tokenAmount: 1n,
}
);
connection?.signAndSendTransaction()

console.log(t1)
console.log(payload)
// console.log(parameter)

alert('calling Transfer')

}

async function viewTokens() {
const contractAddressT = ContractAddress.create(8665n, 0n);
const contract = await CIS2Contract.create(client, contractAddressT);

const tokenId = '00000001'; // HEX string representing a token ID defined in the contract.
const metadataUrl = await contract.tokenMetadata(tokenId);
console.log(metadataUrl);
   alert('tokenmeta '+metadataUrl.url)

}

useEffect(() => {
setActiveConnectorType(BROWSER_WALLET);
}, [setActiveConnectorType]);

return (
<>

  <h1>Call Mint</h1>
  <div className="card">
    <button onClick={() => callMint()}>
      Mint
    </button>
    <button onClick={() => transferTokens()}>
      Transfer
    </button>
    <button onClick={() => viewTokens()}>
      View
    </button>
    <WalletConnectorButton
                    connectorType={BROWSER_WALLET}
                    connectorName="Browser Wallet"
                    connection={connection}
                    {...props}
                />
  </div>

</>

)
}

export default App