0

I have been attempting to use the Solana Labs wallet adapter to create a NFT Staking site. The backend script is on the chain using Gemworks Gem Lab. Currently my front end has functions created by Knox Hutchenson for React port from Vue. My website is coded in NEXT.JS, and the functions are called from outside of return. I have called ConnectionProvider, WalletProvider, and WalletModalProvider inside my return and logging into the wallet works perfectly, as well as discconecting. Then when attempting to call the functions to check for NFT's and query for the farm, ETC. I am getting error

   You have tried to read "publicKey" on a WalletContext without providing one. Make sure to render a WalletProvider as an ancestor of the component that uses WalletContext

My question is how do I call to these functions and provide the current provider to it?

    /* If the user's wallet is not connected, display connect wallet button. */
    return (
      <ConnectionProvider endpoint="https://api.devnet.solana.com">
        <WalletProvider wallets={wallets} autoConnect>
          <WalletModalProvider>
            <div
              style={{
                display: 'flex',
                justifyContent: 'right',
                marginRight: '2em',
              }}
            >
              <WalletMultiButton />
              <WalletDisconnectButton />
            </div>
            <p>{PublicKey}</p>
            <br />
            <br />
            <div className="App">
              <div>
                {!value && !stakedValue && (
                  <p>
                    <button onClick={refreshAll}>Refresh NFTs</button>
                  </p>
                )}
                {value && farmerState === 'unstaked' ? (
                  <>
                    <button onClick={refreshAll}>Refresh NFTs</button>
                    <h2>Reward Value: {rewardValue}</h2>
                    <button onClick={claimRewards}>Claim Rewards</button>
                    <h2>Your Unstaked NFTs</h2>
                    <div className="m-1 card flex justify-center">
                      <ul>
                        {value.map((value, index) => {
                          if (
                            value.onchainMetadata.data.creators[0].address ==
                            process.env.creator_id ||
                            value.onchainMetadata.data.creators[0].address ==
                            process.env.creator_id2 ||
                            value.onchainMetadata.data.creators[0].address ==
                            process.env.creator_id3
                          ) {
                            return (
                              <p>
                                <img
                                  src={value.externalMetadata.image}
                                  alt={value.onchainMetadata.data.name}
                                  width="150"
                                  height="150"
                                ></img>
                                <span>
                                  <br />
                                  <button onClick={() => stakeNft(value)}>
                                    Stake
                                  </button>
                                </span>
                              </p>
                            );
                          }
                        })}
                      </ul>
                    </div>
                  </>
                ) : (
                  <h3></h3>
                )}
                {farmerState == 'staked' && stakedValue && !value ? (
                  <>
                    <button onClick={refreshAll}>Refresh NFTs</button>
                    <h2>Reward Value: {rewardValue}</h2>
                    <button onClick={claimRewards}>Claim Rewards</button>
                    {console.log('state: ', farmerState)}
                    <h2>Your Staked NFTs</h2>
                    <div>
                      <ul>
                        {stakedValue.map((stakedValue) => {
                          return (
                            <p>
                              <img
                                src={stakedValue.externalMetadata.image}
                                alt={stakedValue.onchainMetadata.data.name}
                                width="150"
                                height="150"
                              ></img>
                              <span>
                                <br />
                                <button
                                  onClick={() => withdrawStake(stakedValue)}
                                >
                                  Unstake
                                </button>
                              </span>
                            </p>
                          );
                        })}
                      </ul>
                    </div>
                  </>
                ) : (
                  <>
                    <h2></h2>
                    {console.log('state: ', farmerState)}
                  </>
                )}
                {farmerState == 'staked' && stakedValue && value ? (
                  <>
                    <button onClick={refreshAll}>Refresh NFTs</button>
                    <h2>Reward Value: {rewardValue}</h2>
                    <button onClick={claimRewards}>Claim Rewards</button>
                    <h2>Your Unstaked NFTs</h2>
                    <div className="m-1 card flex justify-center">
                      <ul>
                        {value.map((value, index) => {
                          if (
                            value.onchainMetadata.data.creators[0].address ==
                            process.env.creator_id ||
                            value.onchainMetadata.data.creators[0].address ==
                            process.env.creator_id2 ||
                            value.onchainMetadata.data.creators[0].address ==
                            process.env.creator_id3
                          ) {
                            return (
                              <p>
                                <img
                                  src={value.externalMetadata.image}
                                  alt={value.onchainMetadata.data.name}
                                  width="150"
                                  height="150"
                                ></img>
                                <span>
                                  <br />
                                  <button onClick={() => stakeMoreNfts(value)}>
                                    Stake
                                  </button>
                                </span>
                              </p>
                            );
                          }
                        })}
                      </ul>
                    </div>
                    {console.log('state: ', farmerState)}
                    <h2>Your Staked NFTs</h2>
                    <div>
                      <ul>
                        {stakedValue.map((stakedValue) => {
                          return (
                            <p>
                              <img
                                src={stakedValue.externalMetadata.image}
                                alt={stakedValue.onchainMetadata.data.name}
                                width="150"
                                height="150"
                              ></img>
                              <span>
                                <br />
                                <button
                                  onClick={() => withdrawStake(stakedValue)}
                                >
                                  Unstake
                                </button>
                              </span>
                            </p>
                          );
                        })}
                      </ul>
                    </div>
                  </>
                ) : (
                  <>
                    <button onClick={refreshAll}>Refresh NFTs</button>
                    <h2>No staked NFTs</h2>
                    {console.log('state: ', farmerState)}
                  </>
                )}
              </div>
            </div>
          </WalletModalProvider>
        </WalletProvider>
      </ConnectionProvider>
    );
  }
}

export default Staking;
2
  • Anyway, you can summarise your component hierarchy for us? It sounds like WalletProvider is not further up in the tree from the component that's calling useWallet() hook
    – sohrab
    Aug 6, 2022 at 2:40
  • @sohrab That summary come through bad, I have edited the main question to contain code without the functions.
    – Joshua
    Aug 6, 2022 at 3:16

1 Answer 1

1

You need to move the providers a level up in the component tree. The provider and consumer cannot be defined in the same component.

This is less about WalletProvider specifically and more of a general React thing: https://stackoverflow.com/questions/62947992/how-to-use-context-within-same-component-file-using-react-and-typescript

At the very least, I suggest moving anything after the wallet button div into a sub-component. Although, I can spot a few components that this code can be refactored into.

2
  • Just to make sure that I am understanding correctly, I need to call the code under div as a separate component? (At the minimum, ill refactor when its working) This would move it to being a parent correct? I should also move the functions to the new component as well.
    – Joshua
    Aug 6, 2022 at 4:06
  • Nevermind added const Staking = () => ( <ConnectionProvider endpoint="https://api.devnet.solana.com"> <WalletProvider wallets={wallets} autoConnect> <WalletModalProvider> <App /> </WalletModalProvider> </WalletProvider> </ConnectionProvider> ) export default Staking; and put all inside app. Thank You!
    – Joshua
    Aug 6, 2022 at 4:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.