Skip to content

Add EIP-5320: Harberger Taxes NFT#5320

Closed
greenlucid wants to merge 6 commits intoethereum:masterfrom
greenlucid:master
Closed

Add EIP-5320: Harberger Taxes NFT#5320
greenlucid wants to merge 6 commits intoethereum:masterfrom
greenlucid:master

Conversation

@greenlucid
Copy link
Contributor

No description provided.

@eth-bot
Copy link
Collaborator

eth-bot commented Jul 24, 2022

Hi! I'm a bot, and I wanted to automerge your PR, but couldn't because of the following issue(s):


(fail) eip-5320.md

classification
newEIPFile

@greenlucid greenlucid changed the title Add EIP-XXXX: Harberger Taxes NFT Add EIP-5320: Harberger Taxes NFT Jul 24, 2022
@github-actions
Copy link

The commit bffc802 (as a parent of 213ef96) contains errors. Please inspect the Run Summary for details.

@github-actions
Copy link

The commit e066be5 (as a parent of 213ef96) contains errors. Please inspect the Run Summary for details.

Copy link

@MicahZoltu MicahZoltu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure you address all of the feedback from the bot (see inline comments in files tab in GitHub), and address any CI failures that appear to be problems with the EIP.

@github-actions
Copy link

The commit 6d8c9bd (as a parent of 213ef96) contains errors. Please inspect the Run Summary for details.

Copy link
Member

@Pandapip1 Pandapip1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This EIP is looking good.


### EIP-20 compatibility

EIP-20 compliant tokens are a widespread industry standard and using native tokens is limiting.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One caveat: what if someone makes an EIP-20 token, gives themselves all of it, and then values the NFT at 1 base unit of that token?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's for the Harberger Tax contract to decide. The deployer can define what the allowed currency is. For example, in this implementation the currency is defined at construction time, so you can, for example, make the allowed currency be WETH.

Having a single, enforced currency is not enforced at the standard level, but ideally a contract shouldn't allow any EIP-20 token because it opens up these attacks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you put this in the Security Considerations?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HT may be philosophically incompatible with fungibility because each token, by nature of having a self-assessed valuation, is non-fungible.

greenlucid and others added 2 commits July 27, 2022 13:02
Co-authored-by: Pandapip1 <45835846+Pandapip1@users.noreply.github.com>
Co-authored-by: Pandapip1 <45835846+Pandapip1@users.noreply.github.com>
@github-actions
Copy link

The commit bbccb8f (as a parent of b81b7e4) contains errors. Please inspect the Run Summary for details.

/// @dev call this to change the perceived valuation of the token.
/// @param _tokenId The identifier of the token to change valuation of.
/// @param _valuation The new valuation of the token.
function changeValuation(uint256 _tokenId, uint256 _valuation) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since there's no "tax period", it's hard to know when taxes must be paid for someone who owns this token. I was working with CityDAO on this a proposal for using Harberger taxes on a parcel of land, and one of the things that folks need to know is when the collection period is. You don't want to make it a single date because then folks will try to game the system, and you don't want to make it "all year long" because you don't know when it will actually be assessed.

I wrote up quite a bit of detail here if you want to take a look. It may inform this EIP in some ways to make tax collection more standardized.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdnorman This comment would be better suited for the discussions-to link so it doesn't get lost. Comments on the PR itself should be limited to editorial type things, while comments on the content itself should go in the discussions-to. PRs are very transient in nature, while the discussion link is much more long lived.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. First timer commenting on an EIP. I've copied my commentary to the discussion.

Comment on lines +67 to +72
/// @dev buy a token. This function must succeed if
/// @param _tokenId The identifier of the token to buy.
/// @param _offer The maximum amount offered to buy this token.
/// @param _valuation The valuation the token will have after a successful purchase.
/// @param _fund The fund put in to pay for the taxes of the token.
function buy(uint256 _tokenId, uint256 _offer, uint256 _valuation, uint256 _fund) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specification should make it explicit that when this function is called, collect must be called internally before the sale completes.

Comment on lines +89 to +92
/// @dev call this to manually send pending taxes to the collector.
/// This function should be callable by any external party.
/// @param _tokenId The identifier of the token to pay taxes for.
function collect(uint256 _tokenId) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specification should assert what happens when collect fails for any reason. Presumably the remaining funds would be collected and the NFT's valuation would be set to 0 (which would allow anyone to acquire the property for free)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably the remaining funds would be collected and the NFT's valuation would be set to 0 (which would allow anyone to acquire the property for free)?

Shouldn't this transfer the token to the collector, not set the valuation to zero? The collector is owed taxes, but didn't receive them.

Comment on lines +85 to +87
/// @dev call this to revoke ownership of a token.
/// @param _tokenId The identifier of the token to revoke.
function revoke(uint256 _tokenId) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels unnecessary. The owner can just set the valuation to 0, which would make the property free to acquire by anyone.

Comment on lines +79 to +83
/// @dev call this to remove excess funding for the token.
/// if the resultant fund for the token was zero, it must be revoked.
/// @param _tokenId The identifier of the token to defund.
/// @param _value The amount to retrieve from the token's fund.
function defund(uint256 _tokenId, uint256 _value) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably assert that the valuation gets set to 0 as a side effect of defunding.

Comment on lines +94 to +97
/// @dev call this to change the perceived valuation of the token.
/// @param _tokenId The identifier of the token to change valuation of.
/// @param _valuation The new valuation of the token.
function changeValuation(uint256 _tokenId, uint256 _valuation) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Considerations section should mention that collect SHOULD be called internally from this method prior to changing the valuation to avoid tax evasion.


### Taxes and funds are per token, not per account

This made for a simpler implementation, but it may be too naive. Please give feedback on how to implement this.
Copy link

@JasoonS JasoonS Aug 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still need to go through this more and give my thoughts (at a retreat this week, so might have to wait).

But at https://wildcards.world we had a system where users could share deposits between their harberger NFTs, and the harberger tax of those NFTs could go to multiple different beneficiaries. (hence it is "scalable" for users to own multiple NFTs that share a deposit and fund multiple beneficiaries).

I gave a presentation on this a while ago which can be found here: https://youtu.be/LYm-cVuo0sg and here is the slideshow: Harberger Tax Contract Overview.pdf

Here are those contracts, which might be an interesting reference.

I believe use-cases are limited where there isn't this kind of flexibility, and it would be sad if the contract interface was drastically different between them.

A fun and enlightening task (no promise on timeline) would be to see if I can refactor the Wildcards contracts to be compliant with this EIP 👍

/// @param _owner The owner of the token after the purchase.
/// if equal to address(0), it means the token was revoked.
/// @param _amount The amount that was paid in this transaction.
event TokenBought(uint256 indexed _tokenId, address indexed _owner, uint256 _amount);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Lease" and "Leasor" are a better fit here; one of the core ideas of HT is that an asset within this system cannot be "owed" (as commonly understood within the prevailing contexts of private ownership).

/// fund was updated.
/// @param _tokenId The identifier of the token that had a fund change.
/// @param _amount The updated amount of the fund.
event TokenFunded(uint256 indexed _tokenId, uint256 _amount);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The standard should not assume that a deposit model is necessary. Deposit vs. non-deposit are alternative methods with their own respective tradeoffs (which should be documented as part of this standard).

EIPS/eip-5320.md Outdated
Comment on lines +25 to +32
The main obvious case of Harberger Taxes is to be used as a coordination mechanism for land allocation, but, to give some examples:

- Real-world land allocation.
- Digital land allocation (videogames, social experiments...).
- Advertisement Space in websites.
- Governance mechanisms that use "seats" subject to Harberger.
- Social media that requires holding a token to interact.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These use cases can go in the Motivation section. They don't belong in a technical abstract.

/// @param _value The taxes that have been paid.
event TaxPaid(uint256 indexed _tokenId, uint256 _value);

/// @dev buy a token. This function must succeed if
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to finish this sentence?

Comment on lines +89 to +92
/// @dev call this to manually send pending taxes to the collector.
/// This function should be callable by any external party.
/// @param _tokenId The identifier of the token to pay taxes for.
function collect(uint256 _tokenId) external;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably the remaining funds would be collected and the NFT's valuation would be set to 0 (which would allow anyone to acquire the property for free)?

Shouldn't this transfer the token to the collector, not set the valuation to zero? The collector is owed taxes, but didn't receive them.

Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com>
Co-authored-by: Micah Zoltu <micah@zoltu.net>
@github-actions github-actions bot added c-new Creates a brand new proposal s-draft This EIP is a Draft t-erc labels Aug 28, 2022
@Pandapip1 Pandapip1 added the w-response Waiting on author response label Aug 28, 2022
@github-actions
Copy link

There has been no activity on this pull request for 2 weeks. It will be closed after 3 months of inactivity. If you would like to move this PR forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added w-stale Waiting on activity and removed w-stale Waiting on activity labels Sep 13, 2022
/// @dev call this to fund the item, to pay for the maintenance taxes.
/// @param _tokenId The identifier of the token to fund.
/// @param _value The amount sent to fund the token.
function fund(uint256 _tokenId, uint256 _value) external;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which amount of token is this _value here representing?

@github-actions
Copy link

There has been no activity on this pull request for 2 weeks. It will be closed after 3 months of inactivity. If you would like to move this PR forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the w-stale Waiting on activity label Oct 13, 2022
/// if the resultant fund for the token was zero, it must be revoked.
/// @param _tokenId The identifier of the token to defund.
/// @param _value The amount to retrieve from the token's fund.
function defund(uint256 _tokenId, uint256 _value) external;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to have this function in the standard? If yes, then where exactly should this function be used and what is the benefit of having defunding available for users?

@github-actions github-actions bot removed the w-stale Waiting on activity label Oct 26, 2022
@github-actions
Copy link

There has been no activity on this pull request for 2 weeks. It will be closed after 3 months of inactivity. If you would like to move this PR forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the w-stale Waiting on activity label Nov 12, 2022
@github-actions
Copy link

This pull request was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

@github-actions github-actions bot closed this Dec 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c-new Creates a brand new proposal s-draft This EIP is a Draft t-erc w-response Waiting on author response w-stale Waiting on activity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants