Skip to content

Instantly share code, notes, and snippets.

@frozeman
Last active October 23, 2022 00:47
Show Gist options
  • Save frozeman/090ae32041bcfe120824 to your computer and use it in GitHub Desktop.
Save frozeman/090ae32041bcfe120824 to your computer and use it in GitHub Desktop.
Token proposal

This is outdated: The ERC-20 is here: ethereum/EIPs#20

Token

Methods

totalSupply

function totalSupply() constant returns (uint256 supply)

Get the total coin supply

balanceOf

function balanceOf(address _address) constant returns (uint256 balance)

Get the account balance of another account with address _address

transfer

function transfer(address _to, uint256 _value) returns (bool _success)

Send _value amount of coins to address _to

transferFrom

function transferFrom(address _from, address _to, uint256 _value) returns (bool success)

Send _value amount of coins from address _from to address _to

The transferFrom method is used for a "direct debit" workflow, allowing contracts to send coins on your behalf, for example to "deposit" to a contract address and/or to charge fees in sub-currencies; the command should fail unless the _from account has deliberately authorized the sender of the message via some mechanism; we propose these standardized APIs for approval:

approve

function approve(address _address) returns (bool success)

Allow _address to direct debit from your account with full custody. Only implement if absolutely required and use carefully. See approveOnce below for a more limited method.

unapprove

function unapprove(address _address) returns (bool success)

Unapprove address _address to direct debit from your account if it was previously approved. Must reset both one-time and full custody approvals.

isApprovedFor

function isApprovedFor(address _target, address _proxy) constant returns (bool success)

Returns 1 if _proxy is allowed to direct debit from _target

approveOnce

function approveOnce(address _address, uint256 _maxValue) returns (bool success)

Makes a one-time approval for _address to send a maximum amount of currency equal to _maxValue

isApprovedOnceFor

function isApprovedOnceFor(address _target, address _proxy) returns (uint256 maxValue)

Returns _maxValue if _proxy is allowed to direct debit the returned maxValue from address _target only once. The approval must be reset on any transfer by _proxy of _maxValue or less.

Events

Transfer

event Transfer(address indexed _from, address indexed _to, uint256 _value)

Triggered when tokens are transferred.

AddressApproval

event AddressApproval(address indexed _address, address indexed _proxy, bool _result)

Triggered when an _address approves _proxy to direct debit from their account.

AddressApprovalOnce

event AddressApprovalOnce(address indexed _address, address indexed _proxy, uint256 _value)

Triggered when an _address approves _proxy to direct debit from their account only once for a maximum of _value

@alexvandesande
Copy link

@aakilfernandes I kinda agree with you there but some people might see it differently. Maybe the whole approval model should be left off the official specs and we simply see what everyone else comes up with?

@simondlr It's a good point that you are incurring in extra gas costs for 99% of the uses where the token is being sent to a address or a contract that might not have the hook implemented. But how costly is that? Is there a better way? Because it solves a real problem

@simondlr
Copy link

@frozeman @ethers the problem with adding identifiers is that 1) it costs more to deploy, where most token types won't use it as much, 2) it adds additional complexity. If a normal transfer without identifier is called, should it map to the identifier system? If so, should it default to 0 as the identifier? Or contract address? If it creates separate balances (one with identifiers & one without), then that's a lot of overhead for a standard token to deploy each time?

@alexvandesande I'm not sure how costly it is, but it seems we can have a more elegant solution? The approval tango seems to be fine for things like exchanges (since you can accept that a deposit can be made). For wallets, it can still work like this as well. You approve the wallet to withdraw funds and then a tx is sent to allow it to withdraw funds to the wallet account. Not ideal from a UX perspective though (unless it's all hidden away). You have to issue more than one transaction. The other option is that dapps who work with tokens have an "audit" or "check" button to see if funds have been received so that their internal ledgers can be updated (or whatever else needs to happen).

I guess I'm not sure what the best solution is here. I'd like it to be separated, and not have token contracts prodding recipients the whole time. What do you think?

There are potentially cues we can take from Bitcoin & Ether itself, in the sense that you don't actually send it to someone else. You only allow a new person an approval to send it onwards... I'll have to think some more.

@frozeman
Copy link
Author

I don't see the point of the approval functions honestly..
Why not just simply transfer tokens to some other address. I think this is overly complicated for this early stage

@MrChico
Copy link

MrChico commented Nov 17, 2015

I'm also a fan of skipping the approval functions and keeping things as simple

@niran
Copy link

niran commented Nov 17, 2015

The approval functionality turns many two-transaction scenarios into one-transaction scenarios. Consider Gnosis. As a user in 2016, I have seen the Gnosis contract code and understand that it cannot steal my money. Ethereum guarantees that the contract is immutable, so it is safe for me to give this contract access to my funds. When I want to buy shares, the Gnosis contracts can transfer the amount of funds I specified directly into the pool for the desired prediction market. Without approval, I'd have to transfer funds to Gnosis then buy shares.

The latter flow requires every contract that needs user funds to build its own bank of funds. The bookkeeping for who owns which tokens shouldn't have to be replicated in every contract. Putting approval logic lets contracts assume they can draw funds from the user's token balance without having to do any bookkeeping. If the transfer succeeds, the transaction proceeds. If the transfer fails, the transaction fails. The contracts become considerably simpler.

Yes, approval can be replaced by transferring funds to a contract instead. It is significantly more cumbersome and trivial to avoid.

@niran
Copy link

niran commented Nov 17, 2015

On the other hand, it'd be fine to consider transfer, balanceOf, and the Transfer event as EEP N, then separate the approval parts into EEP N+1. Gnosis and other apps can just declare that they require tokens that implement EEP N and N+1, and we can move on. Token authors want dapps to use their tokens, so I expect that they'll implement both.

EEP = Ethereum Enhancement Proposal, like Python's PEPs. EIP (like BIP) is too hard to say out loud. Maybe that ship has already sailed.

@aakilfernandes
Copy link

I'm not really following the example. Is Gnosis or MyBank implementing the token spec?

Without approval, I'd have to transfer funds to Gnosis then buy shares.

I don't understand this. Can't I do GnosisContract.buy('XYZ',{value:X})?

@niran
Copy link

niran commented Nov 18, 2015

Can't I do GnosisContract.buy('XYZ',{value:X})?

That only works for ether. The approval APIs give tokens similar abilities.

Is Gnosis or MyBank implementing the token spec?

MyDollar is implementing the token spec. Gnosis will have some markets that are denominated in MyDollars, so it needs some of the trader's MyDollar funds.

@ramvi
Copy link

ramvi commented Nov 18, 2015

Many sub currencies will implement some kind of mining. Maybe the standard should say something about that. Either an Event for mining or an agreement that event Transfer from 0x0 is mining

@frozeman
Copy link
Author

I added the totalSupply function

@frozeman
Copy link
Author

One important point is still missing. And this is if we should include the token name, symbol and decimal places into the contract as a public "var".

I definitely think that the decimal places belong there, I'm ok with leaving the name and symbol out.

@vbuterin
Copy link

Some kind of approve, approveOnce or cheque functionality is pretty essential. The basic use case is that contracts will sometimes want to charge fees in subcurrencies, and the callee needs a way to verify that a payment from the caller to the callee was made, and that this payment cannot be used for two calls. The simplest way of doing that is to have this approval/cheque mechanism, and have the callee cash out the cheque. There are other approaches, but their complexity is equal or greater.

I'm fine with the idea of making cheques/approvals transferable.

A few more questions:

  • Does approveOnce approve only one transfer of maximum value _maxValue, or does it approve multiple transfers of maximum total value _maxValue?
  • If the latter, do we even need approve, when we can just do approveOnce(2**100)? I'd consider making approve optional in the spec.
  • Naming preferences? The two choices seem to be approve/approveOnce/isApprovedFor vs something to do with "cheques"
  • Do we want isApprovedFor, or do we want a simple howMuchApproved() function that returns the amount approved?

@frozeman
Copy link
Author

I would rather go with the cheque terminology and would also change the transferFrom to useCheque or so.
I also agree that we don't need an approve function, if the createCheque (approveOne) is enough.

The simpler the better

@simondlr
Copy link

Yeah, I'm with @vbuterin & @niran. Having approval inside the token contract eases up several scenarios such as what was described above (instead of having multiple contracts doing multiple approval tangos).

@vbuterin: There was some ambiguity initially around approveOnce. The current standard was changed so that it only allows 1 time transfer of up to maxValue. Essentially a deposit.

Full custodian approval does seem somewhat questionable & not entirely sure where you will need that. Since, you might as well just send funds to another contract to deal with it?

Perhaps... we change approve() to being the latter approveOnce() as you mentioned. Do we want to specify amount of withdrawals that can be made? Perhaps in subscription scenarios? In most circumstances though, I feel having up to value works for most use cases, even for things like subscriptions. Just leave the right amount in there for a certain time period (for example).

So, we drop approveOnce() and approve() becomes:

function approve(address _address, uint256 _maxValue) returns (bool success)

Which approves _address to withdraw anything up to _maxValue. Thoughts? Regarding transfers of approvals? How would that work? Is it something we want in this current spec at this point in time?

@frozeman

I like useCheque. So perhaps it should then be that we drop approve...

createCheque(address _address, _maxValue)

which is equivalent to allowing _address to withdraw up to _maxValue.

And then? How do we transfer cheques?

@simondlr
Copy link

The only problem with the terminology of cheques is that it seems to be once offs. Not "use many times until all of it has been cashed in".

So: approve, approveOnce & transferFrom gets replaced with createCheque, useCheque & transferCheque (last one tbd)? Where a cheque allows recipient to withdraw multiple times until funds are empty?

@frozeman
Copy link
Author

So basically we get rid of the prove stuff and simple add:

function createCheque(address _address, uint256 _maxValue)
function cashCheque(address _from, address _to, uint256 _maxValue)

This needs first to allow the check receiver and then he can cash in. So technically the same as approveOnce, but more clear imo.

event CreatedCheque(address indexed _for, address indexed _address, uint256 _maxValue)

@simondlr
Copy link

Would this allow proportional cashing of the cheque (such as what @vbuterin described)? ie, if a cheque is created, then you can cash the same one twice, as long as it still fits into the allotted value. So it should perhaps then more read:

function cashCheque(address _from, address _to, uint256 _value)

?

@frozeman
Copy link
Author

true

@tgerring
Copy link

A UI preview of this proposal is available at https://tgerring.github.io/abi2html-js/?SIGNATURE_GIST=090ae32041bcfe120824. You can ignore the "Could not connect to Ethereum client" message, as ABI-to-UI does not require a node.

@vbuterin
Copy link

Yeah, createCheque and cashCheque as above, plus transferCheque(address _from, address _to, uint256 _value) sounds good. In that case, we should probably remove the _to argument from cashCheque; generally, you can only cash cheques from your own bank account.

We probably also want getChequeValue(address _from, address _for). We then have a choice of whether we want to keep the value argument in cashCheque rather than simply only allowing cashing in 100% of whatever is in there. If we want to fully follow the cheque analogy, this triad seems most intuitive to me:

  • function createCheque(address _for, uint256 _maxValue)
  • function cashCheque(address _from)
  • function getChequeValue(address _from, address _for)

Question: does running createCheque twice add the value of the two cheques together? Are there legitimate use cases for creating a cheque multiple times and then cashing either once or multiple times?

@nmushegian
Copy link

All the functions that return uint should return (uint, bool) instead. You can easily make up scenarios where a 0 return value is ambiguous and significant. Is there any other simpler pattern for handling this?

@niran
Copy link

niran commented Nov 18, 2015

I think the value parameter is useful in cashCheque. It absolves callers from having to verify that the amount they needed was provided, and from having to refund amounts greater than what was needed. cashCheque would only succeed if the provided value was remaining in the cheque.

@niran
Copy link

niran commented Nov 18, 2015

Also, I think using createCheque(2**100) for the approve use case is going to lead to less clear code. It gets better if you make the magic number a constant, like createCheque(UNLIMITED_CHEQUE_VALUE), but lots of people won't do that. I think it's worth having a createBlankCheque or something for the approve scenario. Most tokens will use the TokenLib to handle all of the cheque logic, so it doesn't really make things worse for token authors.

@ethers
Copy link

ethers commented Nov 19, 2015

per obscuren's suggestion on Gitter, created this issue for further discussion
ethereum/EIPs#19

@caktux
Copy link

caktux commented Nov 19, 2015

I also think there is a problem with the terminology of cheques since they imply one-offs. Cheques are also unique, and here cheques wouldn't return unique IDs or anything; those are merely approval methods for transfers using internal bookkeeping. I think the current approve/transfer terminology is accurate and simple enough, instead of ending up with a mix of transfer and cashCheque. Would we change unapprove to tearCheque? There's also that ambiguity of cheques adding up, where approvals more clearly override a previous one.

In the use case described by Vitalik of contracts charging fees in subcurrencies, it could easily cost more to have to call approveOnce each time (if we replace the current approve method with it) than the actual fee in subcurrency. For that reason I think we should keep both approve and approveOnce, but we could add the _maxValue argument to the former, that way subscriptions or fees could be taken in multiple calls but only up to a certain amount. Another reason to keep the approval terminology, as I think it's much simpler to describe approve and approveOnce than some createMultiCheque and createCheque. Regarding isApprovedFor, it would have to return the approved amount if we do add _maxValue, just as isApprovedOnceFor does.

@frozeman I'd also like to discuss the addition of decimals, token name and symbol sooner than later. It could really simplify the task of getting a token's basic information into wallets and other dApps, and I think it does belong in a token's contract before a registry.

@frozeman
Copy link
Author

Its pretty hard to keep up with the agreement. I will move this discussion into an ERC in the comments and we can continue there. The advantage is that when we quote each other we get notified via email etc.

Cheque is a very british/american thing, so an european is not so familiar with the details about cheques. Though i thought it sounded a bit more clear than approve.

Please continue here: --------->>>>>>>>>>> ethereum/EIPs#20

@DrZainAzm
Copy link

Investor Protection Laws and Regulations, Securities Arbitration and Mediation, Financial Industry Regulatory Authority - Dispute Resolution, Claims and Fraud Awards 2020. Brief description of the provisions, Fraud Alert: USD $4,290,926.01 the amount of illegal migration in securities fraud practitioners. Refinish a resources for victims of Securities Law Violations and Personal Data Privacy Policy Acts 1974, facilitating quick responses to congressional requests for information and amendment of Securities Acts 1933-Federal Securities Law, Statute Compilations via the Office of the U.S. House of Representatives.

The defendants are found liable and to be responsible, the Attorney At Law must be committed to ensuring a fair and open process for making awards that those assets be distributed to harmed investors and ensure statutory requirements have been met and exceeded expectations of resources for victims of securities law violations acts 1933, Federal Securities Law –SEC.Gov, United States and six counts of aggravated identity-theft of crypto currency funds.

Attorney At Law should review each application to make sure that the information presented is reasonable, understandable, measurable, and achievable, as well as consistent and beyond the expectations of asking for a source of refinement for statutory formula awards requirement.

Six counts of aggravated identity-theft, six counts of filing false documentation for Ethereum-Blockchain Smart Contract account addresses and one count each of sign we are being hacked, e-mail's does not be delivered into the malicious alien receiver’s mail box, so that’s a bounces-back to sender transponder, mail flow settings a penetration detector’s devices and supported by trigger breakers to remove documentary evidence and resulted Non Delivery Report (NDR) fraud, access device fraud, and access to a protected computer in furtherance of fraud:

1). https://bloxy.info/address/0xed5a231ecc0fa775980ad7b86e49872feacd4c8f
Transaction Hash for smart contract account address transition; manually create and illegally edit "Date & Time-Stamp” for ‘BUY /SELL’ tokens fraud:
** (https://etherscan.io/vmtrace?txhash=0x99167c2758e51d5539c3a23d54ff40a74da9ccac3ca2c01ec36f807a8c130a69&type=parity) **

2). https://bloxy.info/address/0xD0AabcfDDBC5b17E403fF016375e27Dc2a8E3C18
Transaction Hash for smart contract account address transition; manually create and illegally edit "Date & Time-Stamp" for ‘BUY/SELL’ tokens fraud:
** (https://etherscan.io/vmtrace?txhash=0x367873973d95dc5a6926a7ce60125a2e767a8c3ffad2ed77f3d46850d17292f0&type=parity) **

3). https://bloxy.info/address/0x2a350c8429ff66b9446fcd12e148cd09438a1f00
Transaction Hash for smart contract account address transition; manually create and illegally edit "Date & Time-Stamp" for ‘BUY/SELL’ tokens fraud:
** (https://etherscan.io/vmtrace?txhash=0x4a638464a7f32c7038a42805534c0e1655e5b041da74a1e00c3c5f15e7866fe7&type=parity) **

4). https://bloxy.info/address/0xcfaf80b93b2c5a6adccceb382d022fcf2d5b2d24
Transaction Hash for smart contract account address transition; manually create and illegally edit "Date & Time-Stamp" for ‘BUY/SELL’ tokens fraud:
** (https://etherscan.io/vmtrace?txhash=0xbb9f1349181e650fda15811f136878a8c1116e96ea7455734b24763c700c5a2d&type=parity) **

5). https://bloxy.info/address/0x2ff2b86c156583b1135c584fd940a1996fa4230b
Transaction Hash for smart contract account address transition; manually create and illegally edit "Date & Time-Stamp" for ‘BUY/SELL’ tokens fraud:
** (https://etherscan.io/vmtrace?txhash=0xec1d5fceeec6e4eb79b831d1859f5b2a944548e0f872e9022c17194d020814e8&type=parity) **

6). https://etherscan.io/address/0x0000000000000000000000000000000000000000
** (Illegally migrating to the Ethereum Blockchain NEW registration account address documentation fraud.) **

Balance Ethereum Tokens: 8,400.238857870150803727
Ethereum Tokens Value: USD $4,290,926.01

That has not been adequately addressed, piracy and/or other 'red' flags related to all record found in the Parity VM Trace Transaction: "Type of Documentation Documentation - manually create fraud and illegally edit "Date & Time-Stamp" for 'BUY/SELL' token fraud and committed to a securities law violations Acts 1933, Federal Securities Laws -SEC.gov, United States.

We founded in the Parity VM Trace Transaction Fraud:
https://etherscan.io/vmtrace?txhash=0x99167c2758e51d5539c3a23d54ff40a74da9ccac3ca2c01ec36f807a8c130a69&type=parity

A total of 1 record found: "Type of Document - manually create and illegally edit "Date & Time-Stamp" is rapidly committed to security law violations act 1933.

Time-stamp: 698 days 10 hours ago manually edit in back-dated year of (2018-12-20 time-stamp 07:00:46 AM +UTC) fraud.

Truly we won the Super Jackpot Prizes in the year of (2019-02-20) - Lucky Bucks Token (LBT) 1,336,820,269 attribute value in USD $4,290,926.01

Date and time-stamp designed to be unlawful contained in the internet coordination Acts 2003 Geneva Declaration and
Data Protection Act 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment