1.0.2 • Published 2 years ago
react-near-18 v1.0.2
Introduction
Inspired by graphql (for the frontend) I decided to do the same for near.
Navigation
- install
- example Quick example
- api
- NearProvider define near in app
- NearEnvironmentProvider switch env (TestNet, MainNet..)
- Config define contracts
- useNearUser complex example
- useNearUser batch Transactions
- useNearQuery use view methods
- useNearMutation use change methods
- contracts
Setup
You'll need to install the package from npm npm i react-near near-api-js
.
Quick Example
// config.ts
const FT_CONTRACT_NAME = 'mfight-ft.testnet';
function useFtContract() {
return useNearContract(FT_CONTRACT_NAME, {
viewMethods: ['ft_balance_of'],
changeMethods: ['ft_transfer'],
});
}
// app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<NearEnvironmentProvider defaultEnvironment={NearEnvironment.TestNet}>
<NearProvider>
<Component {...pageProps} />
</NearProvider>
</NearEnvironmentProvider>
);
}
// page.tsx
function Page() {
const nearUser = useNearUser(FT_CONTRACT_NAME);
const ftContract = useFtContract();
const { data: ftBalance = '0', refetch: refetchFtBalance } = useFtBalanceOf({
contract: ftContract,
variables: { account_id: nearUser.address as string },
poolInterval: 1000 * 60 * 5,
skip: !nearUser.isConnected,
});
const [transfer] = useFtTransfer({
onError: console.log,
gas: NEAR_GAS,
});
const handleTransfer = () =>
transfer({ receiver_id: 'example.near', amount: 1000 }, parseNearAmount('0.01'));
const handleSignIn = () => nearUser.connect();
return (
<div>
{nearUser.isConnected && (
<>
<span>NEAR balance: {nearUser.balance}</span>
<span>FT balance: {formatNearAmount(ftBalance, 24)}</span>
<button onClick={handleTransfer}>transfer ft</button>
</>
)}
{!nearUser.isConnected && <button onClick={receiver_id}>Connect NEAR</button>}
</div>
);
}
Api
NearProvider
Create a context of NEAR in the application
// app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<NearProvider>
<Component {...pageProps} />
</NearProvider>
);
}
function Page() {
const near = useNear(); // nearApi.Near
const wallet = useNearWallet(); // nearApi.WalletConnection
const account = useNearAccount(); // nearApi.Account
const nearUser = useNearUser('example-contract.near');
return (
<>
<span>User Address: {account.address}</span>
<span>Balance: {account.balance} NEAR</span>
</>
);
}
NearEnvironmentProvider
The state of ENV will be saved in a cookie
// app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<NearEnvironmentProvider defaultEnvironment={NearEnvironment.TestNet}>
<Component {...pageProps} />
</NearEnvironmentProvider>
);
}
function Page() {
const nearEnv = useNearEnvironment();
const handleChangeEnv = () => nearEnv.update(NearEnvironment.TestNet);
return (
<>
<span>Current Env: {nearEnv.value}</span>
<button onClick={handleChangeEnv}>switch to testnet</button>
</>
);
}
useNearUser
Everything you need to manage your account
function Page() {
const nearUser = useNearUser('example-contract');
return (
<>
<button onClick={() => nearUser.connect('Title')}>Connect wallet</button>
<button onClick={() => nearUser.disconnect()}>Disconnect wallet</button>
<span>Is Connected: {nearUser.isConnected}</span>
<span>Address: {nearUser.address}</span>
<span>Balance: {nearUser.balance}</span>
<button onClick={() => nearUser.refreshBalance()}>Refresh balance</button>
</>
);
}
Batch transactions
For example, if you need to transfer 2 coins into a liquidity pool in single call
function Page() {
const nearUser = useNearUser('example-contract');
return (
<>
<button
onClick={async () => {
const tx1 = await nearUser.createTransaction(
contracts.ft,
[
nearApi.transactions.functionCall(
'ft_transfer_call',
{
receiver_id: 'contract-1.near',
amount: nearPriceFt,
msg: JSON.stringify({}),
},
NEAR_GAS.toString() as any,
nearApi.utils.format.parseNearAmount('0.01') as any,
),
],
1,
);
const tx2 = await nearUser.createTransaction(
contracts.ft,
[
nearApi.transactions.functionCall(
'ft_transfer_call',
{
receiver_id: 'contract-2.near',
amount: nearPriceFt,
msg: JSON.stringify({}),
},
NEAR_GAS.toString() as any,
nearApi.utils.format.parseNearAmount('0.01') as any,
),
],
1,
);
await nearUser.signTransactions([tx1, tx2]);
}}
>
Batch Transactions
</button>
</>
);
}
Define and use Contracts
Adding contracts to the application
export const NFT_CONTRACT_NAME = 'mfight-nft.near';
export const FT_CONTRACT_NAME = 'mfight-ft.near';
function useFtContract() {
return useNearContract(FT_CONTRACT_NAME, {
viewMethods: ['ft_balance_of'],
changeMethods: ['ft_transfer'],
});
}
function useNftContract() {
return useNearContract(FT_CONTRACT_NAME, {
viewMethods: ['nft_tokens_for_owner', 'nft_metadata', 'nft_tokens'],
changeMethods: ['nft_transfer'],
});
}
// use
function Page() {
const ftContract = useFtContract();
const { data: balance = '0' } = useFtBalanceOf({
contract: ftContract,
variables: {
account_id: 'account.near',
},
});
return <span>FT balance: {formatNearAmount(balance, 24)}</span>;
}
useNearQuery
Calling the view method from the contract
function Page() {
const nearUser = useNearUser('contract.near');
const ftContract = useFtContract();
const {
data: balance = '0', // method result
loading, // waiting for result or error
error, // error, if exists
refetch, // refresh state
} = useNearQuery<string, { account_id: string }>('ft_balance_of', {
contract: ftContract, // contract of method
variables: {
account_id: 'account.near',
}, // arguments of method
poolInterval: 1000 * 60, // refresh state with interval
skip: !nearUser.isConnected, // method will not be called
debug: true, // debug method, print info to console
onError: (err) => console.log(err), // error handler
onCompleted: (res) => console.log(res), // result handler
});
return (
<>
<span>Balance: {formatNearAmount(balance)}</span>
{loading && <span>Loading...</span>}
{error && <span>Error: {error}</span>}
<button onClick={() => refetch({}).catch(console.log)}>Force Refresh</button>
</>
);
}
useNearMutation
Calling the change method from the contract
function Page() {
const nearUser = useNearUser('contract.near');
const ftContract = useFtContract();
const [transfer, { loading, data }] = useNearMutation<
string,
{ receiver_id: string; amount: string }
>('ft_transfer', {
gas: NEAR_GAS, // gas for this method
contract: ftContract, // contract of method
debug: true, // debug method, print info to console
onError: (err) => console.log(err), // error handler
onCompleted: (res) => console.log(res), // result handler
});
return (
<>
<span>Result: {data}</span>
{loading && <span>Loading...</span>}
<button
onClick={() =>
transfer(
{ amount: parseNearAmount('10'), receiver_id: 'account.near' },
parseNearAmount('0.01') as string,
).catch(console.log)
}
>
Tranfer
</button>
</>
);
}
Contracts
NFT
- nft_metadata
- nft_token
- nft_tokens
- nft_tokens_for_owner
- nft_total_supply
- nft_is_approved
- nft_supply_for_owner
- nft_transfer
- nft_transfer_call
- nft_approve
- nft_revoke
- nft_revoke_all
FT
- ft_metadata
- ft_transfer
- ft_transfer_call
- ft_balance_of
- ft_total_supply
MT
- mt_balance_of
- mt_total_supply
- mt_batch_transfer
- mt_batch_transfer_call
Storage
- storage_balance_of
- storage_balance_bounds
- storage_deposit
- storage_withdraw
- storage_unregister
Authors
- Maksim Schiriy @maksim-schiriy