Diffusive Tokens
相关视频
正文
Abstract
This ERC proposes a standard for a new type of fungible token, called Diffusive Tokens (DIFF). Unlike traditional ERC-20 tokens, transferring DIFF tokens does not decrease the sender’s balance. Instead, it mints new tokens directly to the recipient, increasing the total supply on every transfer action. A fixed native currency fee is charged per token transferred, and this fee is paid by the sender to the contract owner. The supply growth is limited by a maximum supply set by the owner. Token holders can also burn their tokens to reduce the total supply. These features enable a controlled, incentivized token distribution model that merges fungibility with a built-in economic mechanism.
Motivation
Traditional ERC-20 tokens maintain a constant total supply and simply redistribute balances on transfers. While this model is widespread, certain use cases benefit from a token design that continuously expands supply during transfers, simulating a controlled "diffusion" of value. The Diffusive Token model may be suitable for representing claims on real-world goods (e.g., a product batch like iPhone 15 units), digital goods, or controlled asset distributions where initial token distribution and ongoing availability need to be managed differently.
This model also includes a native currency fee per token transferred, incentivizing careful, value-driven transfers and providing a revenue stream for the token’s issuer. The maximum supply cap prevents unbounded inflation, ensuring long-term scarcity. The ability for owners to burn tokens to redeem underlying goods or services directly maps on-chain assets to real-world redemptions.
Use Cases:
- 
Real-World Asset Backing: A manufacturer can issue DIFF tokens representing a batch of products (e.g., iPhones). Each token can be redeemed (burned) for one physical item. 
- 
Fee-Driven Incentives: The transfer fee ensures that infinite minting by constant transferring is economically disincentivized. The fee also supports the token issuer or provides a funding mechanism. 
Specification
Terminology
- Diffusive Token: A fungible token unit that is minted on transfers.
- Max Supply: The maximum total supply the token can reach.
- Transfer Fee: A fee in native blockchain currency (e.g., ETH) that must be paid by the sender for each token transferred. The total fee = transferFee * amount.
- Burn: The action of destroying tokens, reducing both the holder’s balance and the total supply.
Data Structures
- 
Total Supply and Max Supply: uint256 public totalSupply; uint256 public maxSupply;
- 
Transfer Fee: uint256 public transferFee; // fee per token transferred in wei address public owner;The ownersets and updatestransferFeeandmaxSupply.
Token Semantics
- 
Minting on Transfer When a transfer occurs from AtoB:- Adoes not lose any tokens.
- Breceives newly minted tokens (increasing their balance and totalSupply).
- The totalSupplyincreases by the transferred amount, but must not exceedmaxSupply.
 
- 
Fixed Transfer Fee in Native Currency Each transfer requires the sender to pay transferFee * amountin the native currency. Ifmsg.valueis insufficient, the transaction reverts.
- 
Maximum Supply If a transfer would cause totalSupply + amount > maxSupply, it must revert.
- 
Burning Tokens Token holders can burn tokens to: - Reduce their balance by the burned amount.
- Decrease totalSupplyby the burned amount.
 This can map to redeeming underlying goods or simply deflating the token. 
Interface
The DIFF standard aligns partially with ERC-20, but redefines certain behaviors:
Core Functions:
- 
function balanceOf(address account) external view returns (uint256);
- 
function transfer(address to, uint256 amount) external payable returns (bool);- Modified behavior: Mints amounttokens toto, requiresmsg.value >= transferFee * amount.
 
- Modified behavior: Mints 
- 
function burn(uint256 amount) external;- Reduces sender’s balance and totalSupply.
 
- Reduces sender’s balance and 
Administration Functions (Owner Only):
- 
function setMaxSupply(uint256 newMax) external;
- 
function setTransferFee(uint256 newFee) external;
- 
function withdrawFees(address payable recipient) external;- Withdraws accumulated native currency fees.
 
Optional Approval Interface (For Compatibility):
- 
function approve(address spender, uint256 amount) external returns (bool);
- 
function transferFrom(address from, address to, uint256 amount) external payable returns (bool);- Modified behavior: Similar to transfer, but uses allowance and still mints tokens totorather than redistributing fromfrom.
 
- Modified behavior: Similar to 
Events
- 
event Transfer(address indexed from, address indexed to, uint256 amount);Emitted when tokens are minted to tovia a transfer call.
- 
event Burn(address indexed burner, uint256 amount);Emitted when amountof tokens are burned from an address.
- 
event FeeUpdated(uint256 newFee);Emitted when the owner updates the transferFee.
- 
event MaxSupplyUpdated(uint256 newMaxSupply);Emitted when the owner updates maxSupply.
Compliance with ERC-20
The DIFF standard implements the ERC-20 interface but significantly alters the transfer and transferFrom semantics:
- Fungibility: Each token unit is identical and divisible as in ERC-20.
- Balances and Transfers: The balanceOffunction works as normal. However,transferandtransferFromno longer redistribute tokens. Instead, they mint new tokens (up tomaxSupply).
- Approvals: The approveandtransferFromfunctions remain, but their logic is unconventional since the sender’s balance is never reduced by transfers.
While the DIFF standard can be seen as ERC-20 compatible at the interface level, the underlying economics differ substantially.
Rationale
Design Decisions:
- 
Unlimited Minting vs. Max Supply: Allowing minting on every transfer provides a “diffusive” spread of tokens. The maxSupplyprevents uncontrolled inflation.
- 
Burn Mechanism: Enables redemption or deflation as tokens are taken out of circulation. 
- 
Owner Controls: The owner (e.g., issuer) can adjust fees and max supply, maintaining flexibility as market conditions change. 
Backwards Compatibility
The DIFF standard is interface-compatible with ERC-20 but not behaviorally identical. Any system integrating DIFF tokens should understand the difference in minting on transfer.
- Wallets and Exchanges: Most ERC-20 compatible tools can display balances and initiate transfers. However, the unusual economics (mint on transfer) may confuse users and pricing mechanisms.
- Allowances and TransferFrom: Still implemented for interoperability, but the expected logic (debiting frombalance) does not apply.
Test Cases
- 
Initial Conditions: - Deploy contract with maxSupply = 1,000,000 DIFF,transferFee = 0.001 ETH.
- totalSupply = 0.
- Owner sets parameters and verifies via maxSupply()andtransferFee()getters.
 
- Deploy contract with 
- 
Minting on Transfer: - User A calls transfer(B, 100)withmsg.value = 0.1 ETH(assumingtransferFee = 0.001 ETH).
- Check balances[B] == 100,totalSupply == 100.
- Check that the contract now holds 0.1 ETH from the fee.
 
- User A calls 
- 
Exceeding Max Supply: - If totalSupply = 999,950and someone tries to transfer 100 tokens, causingtotalSupplyto exceed1,000,000, the transaction reverts.
 
- If 
- 
Burning Tokens: - User B calls burn(50).
- Check balances[B] == 50,totalSupply == 50less than before.
- Burnevent emitted.
 
- User B calls 
- 
Updating Fee and Withdrawing Funds: - Owner calls setTransferFee(0.002 ETH).
- FeeUpdatedevent emitted.
- Owner calls withdrawFees(ownerAddress).
- Check that ownerAddressreceives accumulated fees.
 
- Owner calls 
Reference Implementation
A reference implementation is provided under the asset folder in the EIPs repository. The implementation includes:
- A basic contract implementing the DIFF standard.
contract DiffusiveToken { // ----------------------------------------- // State Variables // ----------------------------------------- string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; uint256 public maxSupply; uint256 public transferFee; // Fee per token transferred in wei address public owner; // ----------------------------------------- // Events // ----------------------------------------- event Transfer(address indexed from, address indexed to, uint256 amount); event Burn(address indexed burner, uint256 amount); event FeeUpdated(uint256 newFee); event MaxSupplyUpdated(uint256 newMaxSupply); event Approval(address indexed owner, address indexed spender, uint256 value); // ----------------------------------------- // Modifiers // ----------------------------------------- modifier onlyOwner() { require(msg.sender == owner, "DiffusiveToken: caller is not the owner"); _; } // ----------------------------------------- // Constructor // ----------------------------------------- /** * @dev Constructor sets the initial parameters for the Diffusive Token. * @param _name Token name * @param _symbol Token symbol * @param _decimals Decimal places * @param _maxSupply The max supply of tokens that can ever exist * @param _transferFee Initial fee per token transferred in wei */ constructor( string memory _name, string memory _symbol, uint8 _decimals, uint256 _maxSupply, uint256 _transferFee ) { name = _name; symbol = _symbol; decimals = _decimals; maxSupply = _maxSupply; transferFee = _transferFee; owner = msg.sender; totalSupply = 0; // Initially, no tokens are minted } // ----------------------------------------- // External and Public Functions // ----------------------------------------- /** * @notice Returns the token balance of the given address. * @param account The address to query */ function balanceOf(address account) external view returns (uint256) { return balances[account]; } /** * @notice Transfers `amount` tokens to address `to`, minting new tokens in the process. * @dev Requires payment of native currency: transferFee * amount. * @param to Recipient address * @param amount Number of tokens to transfer * @return True if successful */ function transfer(address to, uint256 amount) external payable returns (bool) { require(to != address(0), "DiffusiveToken: transfer to zero address"); require(amount > 0, "DiffusiveToken: amount must be greater than zero"); uint256 requiredFee = transferFee * amount; require(msg.value >= requiredFee, "DiffusiveToken: insufficient fee"); // Check max supply limit require(totalSupply + amount <= maxSupply, "DiffusiveToken: would exceed max supply"); // Mint new tokens to `to` balances[to] += amount; totalSupply += amount; emit Transfer(msg.sender, to, amount); return true; } /** * @notice Burns `amount` tokens from the caller's balance, decreasing total supply. * @param amount The number of tokens to burn */ function burn(uint256 amount) external { require(amount > 0, "DiffusiveToken: burn amount must be greater than zero"); require(balances[msg.sender] >= amount, "DiffusiveToken: insufficient balance"); balances[msg.sender] -= amount; totalSupply -= amount; emit Burn(msg.sender, amount); } /** * @notice Approves `spender` to transfer up to `amount` tokens on behalf of `msg.sender`. * @param spender The address authorized to spend * @param amount The max amount they can spend */ function approve(address spender, uint256 amount) external returns (bool) { require(spender != address(0), "DiffusiveToken: approve to zero address"); allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /** * @notice Returns the current allowance of `spender` for `owner`. * @param _owner The owner of the tokens * @param _spender The address allowed to spend the tokens */ function allowance(address _owner, address _spender) external view returns (uint256) { return allowances[_owner][_spender]; } /** * @notice Transfers `amount` tokens from `from` to `to` using the allowance mechanism. * @dev The `from` account does not lose tokens; this still mints to `to`. * @param from The address from which the allowance has been given * @param to The recipient address * @param amount The number of tokens to transfer (mint) */ function transferFrom(address from, address to, uint256 amount) external payable returns (bool) { require(to != address(0), "DiffusiveToken: transfer to zero address"); require(amount > 0, "DiffusiveToken: amount must be greater than zero"); uint256 allowed = allowances[from][msg.sender]; require(allowed >= amount, "DiffusiveToken: allowance exceeded"); // Deduct from allowance allowances[from][msg.sender] = allowed - amount; uint256 requiredFee = transferFee * amount; require(msg.value >= requiredFee, "DiffusiveToken: insufficient fee"); // Check max supply require(totalSupply + amount <= maxSupply, "DiffusiveToken: would exceed max supply"); // Mint tokens to `to` balances[to] += amount; totalSupply += amount; emit Transfer(from, to, amount); return true; } // ----------------------------------------- // Owner Functions // ----------------------------------------- /** * @notice Updates the maximum supply of tokens. Must be >= current totalSupply. * @param newMaxSupply The new maximum supply */ function setMaxSupply(uint256 newMaxSupply) external onlyOwner { require(newMaxSupply >= totalSupply, "DiffusiveToken: new max < current supply"); maxSupply = newMaxSupply; emit MaxSupplyUpdated(newMaxSupply); } /** * @notice Updates the per-token transfer fee. * @param newFee The new fee in wei per token transferred */ function setTransferFee(uint256 newFee) external onlyOwner { transferFee = newFee; emit FeeUpdated(newFee); } /** * @notice Allows the owner to withdraw accumulated native currency fees. * @param recipient The address that will receive the withdrawn fees */ function withdrawFees(address payable recipient) external onlyOwner { require(recipient != address(0), "DiffusiveToken: withdraw to zero address"); uint256 balance = address(this).balance; (bool success, ) = recipient.call{value: balance}(""); require(success, "DiffusiveToken: withdrawal failed"); } // ----------------------------------------- // Fallback and Receive // ----------------------------------------- // Allows the contract to receive Ether. receive() external payable {} }
- Interfaces and helper contracts for testing and demonstration purposes.
Security Considerations
- Reentrancy: Handle fee transfers using the Checks-Effects-Interactions pattern. Consider ReentrancyGuardfrom OpenZeppelin to prevent reentrant calls.
- Overflow/Underflow: Solidity 0.8.x guards against this by default.
- Contract Balance Management: Ensure enough native currency is sent to cover fees. Revert on insufficient fees.
- Access Control: Only the owner can update transferFeeandmaxSupply. Use properonlyOwnermodifiers.
Copyright
Copyright and related rights waived via CC0.