Quick implementation of near in your application. Generation of typed smart contract methods. Including ready for use typed methods in popular smart contract Standards.
- install
- example Quick example
- codegen Generate methods of contract example-codegen
- api
- NearProvider define near in app
- NearEnvironmentProvider switch env (TestNet, MainNet..)
- useNearUser complex example
- useNearUser batch Transactions
- useNearQuery use view methods
- useNearMutation use change methods
- useNearStatus get result (transactions hashes or error)
- contracts
- utils Other utils
You'll need to install the package from npm npm i react-near near-api-js
.
If you need to generate contract methods npm i -D json-schema-to-typescript fzstd
.
// config.ts
const FT_CONTRACT_NAME = 'mfight-ft.testnet';
// app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<NearEnvironmentProvider defaultEnvironment={NearEnvironment.TestNet}>
<NearProvider authContractId='my-contract.testnet'>
<Component {...pageProps} />
</NearProvider>
</NearEnvironmentProvider>
);
}
// page.tsx
function Page() {
const nearUser = useNearUser();
const { data: ftBalance = '0', refetch: refetchFtBalance } = useFtBalanceOf({
contract: 'mfight-ft.testnet',
variables: { account_id: nearUser.address as string },
poolInterval: 1000 * 60 * 5,
skip: !nearUser.isConnected,
});
const [transferCall] = useFtTransferCall({
contract: 'mfight-ft.testnet',
gas: GAS_FOR_FT_TRANSFER_CALL,
});
const handleTransferCall = () =>
transferCall(
{ receiver_id: 'example.near', amount: 1000, msg: JSON.stringify({}) },
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={handleTransferCall}>transfer ft</button>
</>
)}
{!nearUser.isConnected && <button onClick={receiver_id}>Connect NEAR</button>}
</div>
);
}
If you want to generate all the methods of your near contract, you have to:
- you need to add the abi feature, as in this example abi-example
- run
npm i -D json-schema-to-typescript fzstd
- add config to your project
react-near.json
{
"dist": "near-api",
"type": "default", // or "raw", for exclude all hooks
"contracts": [
{
"name": "Nft",
"abi": "abi/nft.json",
"mainnet": "mfight-nft.near",
"testnet": "mfight-nft_v2.testnet"
},
{
"name": "Market",
"mainnet": "mfight-nft.near",
"testnet": "mfight-nft_v2.testnet"
}
]
}
- run script
node ./node_modules/react-near/codegen.js
There is also an example: example-app
Create a context of NEAR in the application
// app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<NearProvider authContractId='my-contract.testnet'>
<Component {...pageProps} />
</NearProvider>
);
}
function Page() {
const near = useNear();
const nearUser = useNearUser();
const nearAccount = useNearAccount(nearUser.address);
return (
<>
<span>User Address: {account.address}</span>
<span>Balance: {nearAccount?.balance} NEAR</span>
</>
);
}
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 = useNearEnv();
const handleChangeEnv = () => nearEnv.update(NearEnvironment.TestNet);
return (
<>
<span>Current Env: {nearEnv.value}</span>
<button onClick={handleChangeEnv}>switch to testnet</button>
</>
);
}
Everything you need to manage your account
function Page() {
const nearUser = useNearUser();
return (
<>
<button onClick={() => nearUser.connect()}>Connect wallet</button>
<button onClick={() => nearUser.disconnect()}>Disconnect wallet</button>
<span>Is Connected: {nearUser.isConnected}</span>
<span>Address: {nearUser.address}</span>
</>
);
}
For example, if you need to transfer 2 coins into a liquidity pool in single call
const MT_CONTRACT_ID = 'mt-token.testnet';
const FT_CONTRACT_ID_1 = 'ft-token-one.testnet';
const FT_CONTRACT_ID_2 = 'ft-token-two.testnet';
const POOL_CONTRACT_ID = 'two-tokens-receiver.testnet';
function Page() {
const nearUser = useNearUser();
const [ftTransferCall1, ftTransferCallCtx1] = useFtTransferCall({
contract: 'mfight-ft.testnet',
gas: GAS_FOR_FT_TRANSFER_CALL,
});
const [ftTransferCall2, ftTransferCallCtx2] = useFtTransferCall({
contract: 'mfight-ft.testnet',
gas: GAS_FOR_FT_TRANSFER_CALL,
});
const [mtBatchTransferCall, mtTransferCallCtx] = useMtBatchTransferCall({
contract: 'mfight-ft.testnet',
gas: GAS_FOR_MT_TRANSFER_CALL,
});
const handleTransfer = async () => {
const amount1 = parseNearAmount('1') as string;
const amount2 = parseNearAmount('1') as string;
return nearUser.signAndSendTransactions({
transactions: [
{
signerId: nearUser.address as string,
receiverId: MT_CONTRACT_ID,
actions: [
{
type: 'FunctionCall',
params: {
methodName: 'ft_transfer',
args: btoa(JSON.stringify({ receiver_id: 'xx', amount: '1' })),
gas: 'xxx',
deposit: '1',
},
},
],
},
],
});
};
return (
<>
<button onClick={handleTransfer}>Batch Transactions</button>
</>
);
}
Calling the view method from the contract
function Page() {
const nearUser = useNearUser();
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: 'mfight-ft.testnte', // 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>
</>
);
}
Calling the change method from the contract
function Page() {
const nearUser = useNearUser();
const [transfer, { loading, data }] = useNearMutation<
string,
{ receiver_id: string; amount: string }
>('ft_transfer', {
gas: NEAR_GAS, // gas for this method
contract: 'mfight-ft.testnet',
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>
</>
);
}
Get result transactions hashes if method is success, or get error if failure
function Page() {
const { transactionHashes, error } = useNearStatus();
return (
<>
{transactionHashes && <span>Success Tx List: {transactionHashes}</span>}
{error && <span>{error}</span>}
</>
);
}
- nft_metadata
- nft_token
- nft_transfer
- nft_transfer_call
- nft_tokens
- nft_tokens_for_owner
- nft_total_supply
- nft_supply_for_owner
- nft_is_approved
- nft_approve
- nft_revoke
- nft_revoke_all
- nft_payout
- nft_transfer_payout
- ft_metadata
- ft_transfer
- ft_transfer_call
- ft_balance_of
- ft_total_supply
- mt_balance_of
- mt_total_supply
- mt_batch_transfer
- mt_batch_transfer_call
- storage_balance_of
- storage_balance_bounds
- storage_deposit
- storage_withdraw
- storage_unregister
- nft_approve (useParasNftApprove)
- get_market_data (useParasMarketData)
- api collection-stats (useParasCollectionStats)
- get_pool (useRefFinancePool)
- parseNearAmount with decimals
- isValidNearAddress
- parseNearDate
- formatNearAddress
- gas and more :)
- Maksim Schiriy @maksim-schiriy