From 30ebe04db757ca96a60f784b28b926ba777b03e1 Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Thu, 2 Feb 2023 21:52:39 -0600 Subject: [PATCH] Add erc20 implementation --- forum-network/src/classes/erc20.js | 154 +++++++++++++++++++ forum-network/src/classes/erc721.js | 4 +- forum-network/src/classes/forum.js | 2 +- forum-network/src/classes/validation-pool.js | 2 +- 4 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 forum-network/src/classes/erc20.js diff --git a/forum-network/src/classes/erc20.js b/forum-network/src/classes/erc20.js new file mode 100644 index 0000000..c305f24 --- /dev/null +++ b/forum-network/src/classes/erc20.js @@ -0,0 +1,154 @@ +/** + * Note: Copied from openzepplin-contracts/contracts/token/ERC20/ERC20.sol + * As of commit d59306b: Improve ERC20.decimals documentation (#3933) + * on 2023-02-02 + * by Ladd Hoffman + * + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * + * --- + * + * This Javascript implementation is incomplete. It lacks the following: + * - allowance + * - transferFrom + * - approve + * - increaseAllowance + * - decreaseAllowance + * - _beforeTokenTransfer + * - _afterTokenTransfer + */ +export class ERC20 { + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + * @param {string} name + * @param {string} symbol + */ + constructor(name, symbol) { + this.name = name; + this.symbol = symbol; + this.totalSupply = 0; + this.balances = new Map(); // + this.allowances = new Map(); // + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + static decimals() { + return 18; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + balanceOf(account) { + return this.balances.get(account); + } + + /** + * @dev See {IERC20-transfer}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + transfer(from, to, amount) { + if (!from) throw new Error('ERC20: transfer from the zero address'); + if (!to) throw new Error('ERC20: transfer to the zero address'); + + // _beforeTokenTransfer(from, to, amount); + + const fromBalance = this.balances.get(from); + if (fromBalance < amount) throw new Error('ERC20: transfer amount exceeds balance'); + this.balances.set(from, fromBalance - amount); + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. + this.balances.set(to, this.balances.get(to) + amount); + + // emit Transfer(from, to, amount); + + // _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + mint(account, amount) { + if (!account) throw new Error('ERC20: mint to the zero address'); + + // _beforeTokenTransfer(address(0), account, amount); + + this.totalSupply += amount; + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. + this.balances.set(account, this.balances.get(account) + amount); + // emit Transfer(address(0), account, amount); + + // _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + burn(account, amount) { + if (!account) throw new Error('ERC20: burn from the zero address'); + + // _beforeTokenTransfer(account, address(0), amount); + + const accountBalance = this.balances.get(account); + if (accountBalance < amount) throw new Error('ERC20: burn amount exceeds balance'); + this.balances.set(account, accountBalance - amount); + // Overflow not possible: amount <= accountBalance <= totalSupply. + this.totalSupply -= amount; + // emit Transfer(address(0), account, amount); + + // _afterTokenTransfer(address(0), account, amount); + } +} diff --git a/forum-network/src/classes/erc721.js b/forum-network/src/classes/erc721.js index 246dac3..5b2b215 100644 --- a/forum-network/src/classes/erc721.js +++ b/forum-network/src/classes/erc721.js @@ -9,7 +9,7 @@ * - Emitting events */ -export class ERC721 /* is ERC165 */ { +export class ERC721 { constructor(name, symbol) { this.name = name; this.symbol = symbol; @@ -59,7 +59,7 @@ export class ERC721 /* is ERC165 */ { return owner; } - transferFrom(from, to, tokenId) { + transfer(from, to, tokenId) { const owner = this.owners.get(tokenId); if (owner !== from) { throw new Error('ERC721: transfer from incorrect owner'); diff --git a/forum-network/src/classes/forum.js b/forum-network/src/classes/forum.js index e099bae..9a1c671 100644 --- a/forum-network/src/classes/forum.js +++ b/forum-network/src/classes/forum.js @@ -84,7 +84,7 @@ export class Forum extends ReputationHolder { } // Transfer ownership of the minted/staked token, from the posts to the post author - this.dao.reputation.transferFrom(this.id, post.authorPublicKey, post.tokenId); + this.dao.reputation.transfer(this.id, post.authorPublicKey, post.tokenId); // const toActor = window?.scene?.findActor((actor) => actor.reputationPublicKey === post.authorPublicKey); // const value = this.dao.reputation.valueOf(post.tokenId); } diff --git a/forum-network/src/classes/validation-pool.js b/forum-network/src/classes/validation-pool.js index 92a85e3..39b1638 100644 --- a/forum-network/src/classes/validation-pool.js +++ b/forum-network/src/classes/validation-pool.js @@ -259,7 +259,7 @@ export class ValidationPool extends ReputationHolder { console.log(`sending reward for author stake to forum: ${this.dao.reputation.valueOf(this.tokenId)}`); // Transfer ownership of the minted token, from the pool to the forum - this.dao.reputation.transferFrom(this.id, this.dao.forum.id, this.tokenId); + this.dao.reputation.transfer(this.id, this.dao.forum.id, this.tokenId); // const value = this.dao.reputation.valueOf(this.tokenId); // this.actions.transfer.log(this, this.dao.forum, `(${value})`);