npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@turkmenson/user-caring

v0.0.1

Published

A framework to recover NFTs and tokens sent to a wrong smartcontract

Readme

Zero deployment cost recovery of lost assets (both nft and crypto)

Let's assume that user sent some nft to a wrong smartcontract. There is no way to recover them unless the developer didn't add that functionality. In other example, what if a user sent the tokens to the address of the token itself? There is no way to return them back.

Due to technical limitations you can't prevent it programmatically. The smartcontracts don't have a way to look to the past transactions. Simply adding a control to withdraw tokens or nfts is not enough. The owner of the smartcontract has to check the transactions to verify the transfer.

That's why developers aren't building it, as they have to put a lot of effort in recovery without getting anything in back.

User Caring is a trust-less, automatic user's asset recovery with zero cost or maintain for the developers. The only thing for the developers is to extend their smartcontracts from UserCaring and pass the recovering contract address:

import { UserCaring } from "ahmetson/user-caring/contracts/UserCaring.sol";

contract Sample is UserCaring {
  constructor(address _userInterface) UserCaring(_userInterface) {}
}

Todo

An upgradable smartcontracts can support user lock. Later I need to add instructions on how to turn upgradable smartcontract to care about the users.

Two parts

The package comes with two smartcontracts. UserCaring is the contract to be used by the developers. This contract adds the control to recover the smartcontracts.

The MyManager is the interface for the users. Through this interface users are requesting the token that they sent to a wrong contract.

There are two reasons to have a split smartcontracts.

  • First to have a nice user centric UI supported by the community. The developers don't have to run UI to recover the lost data.
  • Second, to reduce the smartcontract size from duplicate code.
  • And to secure users from price fees so that developers don't change it in the future. The goal is to provide a right balance to recover the price.

UserInterface

The UserInterface is the smartcontract that acts the interface to recover the lost tokens. The smartcontract's duty is to verify the validness of the transaction hash, and then attempt to recover the lost tokens.

The verification of the transaction is automatic and trustless. The given transaction hash is verified on the multiple public RPC nodes via a Chain Link Oracles.

The UserInterface interface:

interface UserInterface {
    function recoverMyNft(byte[] calldata txHash, address targetContract, address token, uint tokenId) payable external;
    function recoverMyToken(byte[] calldata txHash, address targetContract, address token, uint amount) payable external;
    function removeUrl(byte[] calldata url) external;
    function addUrl(byte[] calldata url) external;
}

Todo

Add a DAO control for the removeUrl and addUrl functions.

//
// in the user-caring page, he puts the transaction hash along with the type of transfer.
// for testing purpose I put the price in the fixed rate. But later I
// would add a dynamic price allocation using Chainlink price feeds.
//
// now let's assume that user sent some token.
// If it's a token, then 0.1 point of tokens are transferred to the owner of contract.

UserCaring

This smartcontract adds a support to return the locked tokens. It's indended to be called by a UserInterface. The latter contract will verify the transaction then it will initiate the recovery.

This smartcontract will have four methods:

interface UserCaring {
    function recoverUserNft(address nftAddress, address to, uint tokenId) external; // invoked by the 
    function recoverUserToken(address token, address to, uint amount) external;
    function setCaringSupporter(address newOwner) external; // change the address that receives the reward.
    function caringSupporter() external returns(address);
}

The first two functions are called by the user's interface. Therefore they have a modifier onlyUserInterface. The caring supporter is the address of the smartcontract owner that gets the rewards for caring the users.

Preventing Load

Some dapps require the user assets. For example games, bridges or staking contracts may lock the asset. To prevent recovering them the UserCaring provides the functions. Simply put them in the functions that locks/burns:

    contract UserCaring {
        constructor(address userInterface) UserCaring(userInterface) {}

        modifier intentionalNftAdd(address nft, address user, uint tokenId) {};
        modifier intentionalNftRemove(address nft, address user, uint tokenId);

        modifier intentionalTokenAdd(address token, address user, uint tokenId) {};
        modifier intentionalTokenRemove(address token, address user, uint tokenId);
    }