Cannot read property 'prefix' of undefined Error when call smart contract

I’m building an E platform project where users can purchase in NEAR using React and typescript. I get that error when I click to confirm the transaction:

Sorry an error has occurred. You may want to try again.

{"index":0,"kind":{"ExecutionError":"Smart contract panicked: cannot read property 'prefix' of undefined\n at reconstruct (build/hello_near.js:1017)\n at _reconstruct (build/hello_near.js:1131)\n at purchaseBasket (build/hello_near.js:1207)\n"}}, 

The smart contract is written in typescript:

import { NearBindgen, near, call, view, UnorderedMap, initialize } from 'near-sdk-js';

@NearBindgen({})

class MyContract {
    beneficiary: string = "mywallet.testnet";

    orders = new UnorderedMap<Order[]>("orders");

    @initialize({ privateFunction: true })
    init({ beneficiary }: { beneficiary: string }) {
        this.beneficiary = beneficiary
    }

    @call({payableFunction: true})
    purchaseBasket({basket, totalPrice}: {basket: OrderItem[]; totalPrice: number}) {
        near.log(basket, totalPrice);
        // Get who is paying
        let sender = near.predecessorAccountId();
        let donationAmount: bigint = near.attachedDeposit() as bigint;
        near.log(sender, donationAmount);

        // Send NEAR token to the beneficiary
        const promise = near.promiseBatchCreate(this.beneficiary)
        near.promiseBatchActionTransfer(promise, donationAmount);

        // Update sender orders
        let currentOrders = this.orders.get(sender, {defaultValue: []}) || [];
        near.log(currentOrders);
        currentOrders.push({
            items: basket,
            totalPrice: totalPrice,
            timestamp: near.blockTimestamp()
        });
        near.log(currentOrders);
        this.orders.set(sender, currentOrders);
        near.log(this.orders);
    }

    @view({})
    getOrders({accountId}: {accountId: string}): Order[] {
        let ordersList = this.orders.get(accountId, {defaultValue: []});
        return ordersList;
    }
}
class OrderItem {
    id: string;
    name: string;
    priceInDollar: number;
    url: string;
    quantity: number;
}

class Order {
    items: OrderItem[];
    totalPrice: number;
    timestamp: bigint;
}

Note that none of the near.log() log anything in the web inspector.
And this is where the call method is called:

import React, {useState, useEffect} from 'react';

import {addToBasket, removeFromBasket, removeItemFromBasket, resetBasket} from '../app/basketSlice.js';
import {useSelector, useDispatch} from 'react-redux';

import Container from 'react-bootstrap/Container';
import Button from 'react-bootstrap/Button';
import Card from 'react-bootstrap/Card';
import Spinner from 'react-bootstrap/Spinner';

import {Img} from 'react-image';

import '../assets/global.css';

import {utils} from 'near-api-js';

export const Basket = ({isSignedIn, contractId, wallet}) => {

    const [nearToDollar, setNearToDollar] = useState(0);

    const basket = useSelector(state => state.items);
    const total = useSelector(state => state.totalPrice);
    const dispatch = useDispatch();

    useEffect(() => {
        const getNearToDollar = async() => {
            let data = await fetch("https://api.coingecko.com/api/v3/simple/price?ids=near&vs_currencies=usd").then(response => response.json())
            const near2usd = data['near']['usd']
            const amount_in_near = 1 / near2usd
            const rounded_two_decimals = Math.round(amount_in_near * 100) / 100;
            setNearToDollar(rounded_two_decimals);
        }
        getNearToDollar();
    }, []);

    const handleOrder = async() => {
        const amountInNear = total*nearToDollar;
        let deposit = utils.format.parseNearAmount(amountInNear.toString());
        return await wallet.callMethod({
            contractId: contractId,
            method: 'purchaseBasket',
            args: {
                basket: basket,
                totalPrice: total
            },
            deposit
        })
        
    }

    const connect = () => {wallet.signIn()}

    const handleResetBasket = () => {
        dispatch(resetBasket());
    }

    const handleAddToBasket = (item) => {
        dispatch(addToBasket(item));
    }

    const handleRemoveFromBasket = (item) => {
        dispatch(removeFromBasket(item));
    }

    const handleRemoveItem = item => {
        dispatch(removeItemFromBasket(item));
    }

    return (
        <Container>
            <div className='mt-5 mb-5 d-flex justify-content-between'>
                <h1>Your Basket</h1>
                <Button onClick={handleResetBasket}>Reset Basket</Button>
            </div>
            <Container className='d-flex flex-wrap justify-content-center'>
                {basket.map((item, index) => {
                    return (
                        <Card className='d-flex flex-column m-2' key={index} style={{ width: '18rem' }}>
                            <Img className='m-1' variant="top" src={item.url} loader={<Spinner animation="border" role="status"></Spinner>}/>
                            <Card.Body className='d-flex flex-column justify-content-end'>
                                <Card.Title className='d-flex justify-content-between'>
                                    <div>{item.name}</div>
                                    <div>{item.quantity}</div>
                                </Card.Title>
                                <Card.Text>
                                    $ {item.priceInDollar*item.quantity} = {item.priceInDollar*nearToDollar*item.quantity} Ⓝ 
                                </Card.Text>
                                <div className='d-flex justify-content-between'>
                                    <Button className='rounded-button' variant='secondary' onClick={() => handleAddToBasket(item)}>+</Button>
                                    <Button className='rounded-button' variant='secondary' onClick={() => handleRemoveFromBasket(item)}>-</Button>
                                    <Button variant="danger" onClick={() => handleRemoveItem(item)}>Remove</Button>
                                </div>
                            </Card.Body>
                        </Card>
                    ) 
                })}
            </Container>
            <h3>Total: $ {total} = {nearToDollar*total} Ⓝ </h3>
            {isSignedIn? (
                <Button onClick={handleOrder}>Buy</Button>
            ) : (
                <Button onClick={connect}>Connect Wallet</Button>
            )}
        </Container>
    )
}

Do you have any idea what I’m doing wrong?
Thanks.

1 Like

Hi @neuneu I’m not a dev so cannot offer you a solution but you can also ask your question in dev-support channel in NEAR Discord. Hope your issue will be resolved soon!

1 Like

Sorry for the late reply, here are some potential issues that could cause bugs for the first snippet:

  1. The OrderItem and Order classes are not imported, so they may cause issues if they are not defined elsewhere in the code.
  2. The beneficiary variable is hard-coded to "mywallet.testnet". It is not clear whether this is the intended behavior or whether it should be set dynamically.
  3. The getOrders function does not have a decorator for its arguments. It is possible that this may cause issues with the function’s behavior.
  4. The near.attachedDeposit() function returns a string, but it is being cast to a bigint. This may cause issues if the attached deposit is not a valid bigint.
  5. The promiseBatchCreate function is being called with a single argument. According to the near-sdk-js documentation, this function takes two arguments: a list of actions and an optional transaction metadata object.
  6. The promiseBatchActionTransfer function is being called with a single argument. According to the near-sdk-js documentation, this function takes three arguments: a batch promise, the recipient account ID, and the transfer amount.

For the second snippet:

  1. The basket, total, and isSignedIn props are assumed to be defined, but there is no check for their existence before using them. This could lead to runtime errors if they are not provided.
  2. The handleOrder function assumes that the wallet object is defined and has a callMethod method. It might be a good idea to add a check for the existence of these before calling the method.
  3. The handleAddToBasket, handleRemoveFromBasket, and handleRemoveItem functions assume that the dispatch function is defined. It might be a good idea to add a check for the existence of dispatch before using it.
  4. The Img component from the react-image library is used without a fallback src attribute. This means that if the image fails to load, there will be no alternative displayed. It might be a good idea to add a src attribute with a placeholder image URL or a fallback component to handle errors.

Try to double check all of these and if it is still not working, pls follow @chi.ha 's suggestion

1 Like

Hi, thanks for your response both.
Yes my smart contract can certainly be written better but I don’t think there was any error.
I couldn’t explain why but I removed my build/, neardev/ and node_modules/ folders, then run npm install and npm run deploy and it was all working fine…