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.