• Set a profile's metadata.

    You MUST be authenticated via useLogin to use this hook.

    Returns UseDeferredTask<AsyncTransactionResult<void>, BroadcastingError | InsufficientGasError | PendingSigningRequestError | UserRejectedError | WalletConnectionError, UseSetProfileMetadataArgs>

    Example

    const { execute, error, loading } = useSetProfileMetadata();
    

    Basic usage

    Update profile metadata with name and bio with location and website attributes.

    const { execute, error, loading } = useSetProfileMetadata();

    const update = async (name: string, bio: string) => {
    // create the desired metadata via the `@lens-protocol/metadata` package helpers
    const metadata = profile({ name, bio });

    // upload the metadata to a storage provider of your choice (IPFS in this example)
    const uri = await uploadToIpfs(metadata);

    // invoke the `execute` function to create the post
    const result = await execute({
    metadataURI: uri,
    });
    };

    See @lens-protocol/metadata for more information on how to create metadata.

    Failure scenarios

    You can handle possible failure scenarios by checking the result value.

    const update = async (name: string, bio: string) => {
    // the first part is the same as in the initial example

    // invoke the `execute` function
    const result = await execute({
    metadataURI: uri,
    });

    if (result.isFailure()) {
    switch (result.error.name) {
    case 'BroadcastingError':
    console.log('There was an error broadcasting the transaction', error.message);
    break;

    case 'PendingSigningRequestError':
    console.log(
    'There is a pending signing request in your wallet. ' +
    'Approve it or discard it and try again.'
    );
    break;

    case 'WalletConnectionError':
    console.log('There was an error connecting to your wallet', error.message);
    break;

    case 'UserRejectedError':
    // the user decided to not sign, usually this is silently ignored by UIs
    break;
    }
    return;
    }
    };

    At this point the profile update is completed from an end-user perspective but, in case of on-chain TX, this is not necessarily mined and indexed (yet). See the following section.

    Wait for completion

    In case of successful submission, the result value can be used to wait for the profile metadata to be fully processed.

    const update = async (name: string, bio: string) => {
    // the first part is the same as in the initial example

    // invoke the `execute` function
    const result = await execute({
    metadataURI: uri,
    });

    if (result.isFailure()) {
    // handle failure scenarios
    return;
    }

    // this might take a while depending the congestion of the network
    const completion = await result.value.waitForCompletion();

    if (completion.isFailure()) {
    console.log('There was an processing the transaction', completion.error.message);
    return;
    }

    // the transaction is fully processed
    };

    Self-funded approach

    It just takes a single parameter to disable the sponsorship of the transaction gas costs.

    const update = async (name: string, bio: string) => {
    // the first part is the same as in the initial example

    // invoke the `execute` function
    const result = await execute({
    metadataURI: uri,
    sponsored: false // <--- this is the only difference
    });

    if (result.isFailure()) {
    switch (result.error.name) {
    case 'InsufficientGasError':
    console.log('You do not have enough funds to pay for the transaction gas cost.');
    break;

    // ...
    }
    return;
    }

    // ...
    }

    In this example you can also see a new error type: InsufficientGasError. This error happens only with self-funded transactions and it means that the wallet does not have enough funds to pay for the transaction gas costs.

    Self-funded fallback

    If for some reason the Lens API cannot sponsor the transaction, the hook will fail with a BroadcastingError with one of the following reasons:

    In those cases you can retry the transaction as self-funded like in the following example:

    const update = async (name: string, bio: string) => {
    // the first part is the same as in the initial example

    // sponsored attempt
    const sponsoredResult = await execute({
    metadataURI: uri,
    sponsored: false
    });

    if (sponsoredResult.isFailure()) {
    switch (sponsoredResult.error.name) {
    case 'BroadcastingError':
    if ([BroadcastingErrorReason.NOT_SPONSORED, BroadcastingErrorReason.RATE_LIMITED].includes(sponsoredResult.error.reason)) {

    const selfFundedResult = await execute({
    metadataURI: uri,
    sponsored: false
    });

    // continue with selfFundedResult as in the previous example
    }
    break;

    // ...
    }
    }

    In this example we omitted BroadcastingErrorReason.APP_NOT_ALLOWED as it's not normally a problem per-se. It just requires the app to apply for whitelisting. See https://docs.lens.xyz/docs/gasless-and-signless#whitelisting-your-app.

    You can still include it in your fallback logic if you want to. For example to unblock testing your app from a domain that is not the whitelisted one (e.g. localhost).