Interactions with contract
This page presents how to implement the DApp's interactions with the smart contract.
Connect to wallet utilities
The src/dapp.js
file defines the necessary utilities to connect the DApp to the blockchain via the Temple wallet:
- check whether wallet is connected
- get the Taquito's object
- ...
In order to make it available accross the React project, these methods are managed with a Constate storage. Constate provides a local centralized storage for React project with minimum effort.
dapp.js
defines a node DAppProvider
that needs to be wrap the App node. The FIX ME section is to be found line 53 in src/DApp.js
file:
function App() {
return (
///////////////////////////////////////////////////////////////////////////
// FIX ME
// Wrap the App's body with <DAppProvider> tag/function in order to benefit
// from wallet's service as defined in dapp.js
///////////////////////////////////////////////////////////////////////////
<React.Suspense fallback={null}>
<PageRouter />
</React.Suspense>
);
}
The code below shows how to declare the DAppProvider
so that it makes the Thanos utilities available to the DApp:
function App() {
return (
<DAppProvider appName={appName}>
<React.Suspense fallback={null}>
<PageRouter />
</React.Suspense>
</DAppProvider>
);
}
Copy-paste the code above.
Read contract storage
The Miles
component defined in src/components/Miles.js
displays the time before next expiration date. The first step defines a React useEffect
hook to read the miles's data for the connected account:
const Miles = (props) => {
/////////////////////////////////////////////////////////////////////////////
// The 'account' variable retrieved from 'dapp.js' is the connected account
// address
/////////////////////////////////////////////////////////////////////////////
const account = useAccountPkh();
/////////////////////////////////////////////////////////////////////////////
// The 'tezos' variable retrieved from 'dapp.js' is used to interact with the
// blockchain
/////////////////////////////////////////////////////////////////////////////
const tezos = useTezos();
useEffect(() => {
///////////////////////////////////////////////////////////////////////////
// FIX ME:
// the goal here is to read the contract storage to extract miles' info
// for the connected 'account' and invoke the 'props.handleMiles' function
// defined in App.js; it takes 2 arguments:
// * contract object itself
// * list of miles data { id; amount; expration } for the account 'address'
///////////////////////////////////////////////////////////////////////////
}, [props.nbMiles]);
return (
<Container style={{ height: '300px'}}>
...
</Container>);
}
The goal of the hook is to build an array of objects providing for the current connected account:
- miles' id
- amount of miles
- expiration date of the miles
The role of the Taquito library is to retrieve the contract data and provide it as a plain javascript object that is straightforward to read.
Here the javascript object of the smart contract's storage provides the following members:
owner
is the list of miles' owners providing:- address
- list of miles'ids
mile
is the list of miles providing:- miles id
- amount
- expiration
The code below tests if the connected account account
is present in the storage. If it exists, miles' data is retrieved in mile
member for each of the account
's miles'id:
useEffect(() => {
tezos.wallet.at(contractAddress).then(contract => {
contract.storage().then(storage => {
var dappMiles = [];
if (storage.owner.has(account)) {
storage.owner.get(account).forEach(mid => {
var mile = storage.mile.get(mid);
dappMiles.push({
id : mid,
amount : mile.amount,
expiration : mile.expiration
});
});
}
props.handleMiles(contract, dappMiles);
})
});
}, [props.nbMiles]);
Copy-paste the code above for the DApp to read the contract storage.
The Taquito's contract object is retrieved with the following code:
tezos.wallet.at(contractAddress).then(contract => {
...
});
The Taquito's contract's storage object is retrieved with the following code:
contract.storage().then(storage => {
...
}
Call entry point
The ProductButton
component defined in /src/components/Products.js
is the 'Get it' button at the bottom of the product item.
When clicked, the handleClick
method is executed.
function ProductButton(props) {
const handleClick = () => {
///////////////////////////////////////////////////////////////////////////
// FIX ME
// The goal is to call the 'consume' contract's entry point. The number of
// miles to consume is 'props.nbmiles'.
// On the UI front, the snack bar should be opened whith 'props.openSnack()'
// while the transaction is confirmed, and closed when confirmed with
// 'props.closeSnack()'.
// The 'receipt()' method of the operation is used to know when the
// transaction is confirmed.
///////////////////////////////////////////////////////////////////////////
}
return (
...
);
}
The consume
entry point must be invoked by the connected account; it takes one parameter that is the number of miles to subtract or delete.
The Taquito library provides methods named as the contract's entry points to make it very simple to call the contract. These methods/entry point take the same arguments as the contract's.
The code below calls the consume
entry point:
const handleClick = () => {
props.contract.methods.consume(props.nbmiles).send().then(op => {
console.log(`waiting for ${op.opHash} to be confirmed`);
props.openSnack();
op.receipt().then(() => {
props.handleReceipt();
});
})
}
Copy-paste the code above to call the contract.
Note that calling the consume
entry point returns an Operation object. This object provides the receipt
method which returns when the operation is confirmed.
The openSnack
and closeSnack
methods open and close (via handleReceipt
) the snack popup to inform the user that a confirmation is waited for.