Created
August 17, 2022 17:34
-
-
Save wrightkhlebisol/c0244c61a3385fbee5e558da0942af0f to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.15+commit.e14f2714.js&optimize=true&runs=100000&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: Unlicensed | |
pragma solidity 0.8.15; | |
import "./RelationshipManager.sol"; | |
contract AccountsFactory { | |
/* | |
* We deploy new contracts for each user and then call those contracts method, | |
that way events and state changes can easily be managed | |
---- Contract 1: Manages Accounts | |
---- Contract 2: Manages Relationships | |
*/ | |
uint256 public constant IDENTITY_TOKEN = 1; | |
uint256 public constant RELATIONSHIP_TOKEN = 2; | |
uint256 public s_initialRelationshipQuantity; | |
address public s_admin; | |
mapping(address => RelationshipContractDetails) public s_relationshipContractDetails; | |
struct RelationshipContractDetails{ | |
bool status; | |
address contractAddress; | |
} | |
enum AccountType{ | |
AIRDROPPED, | |
LINKED | |
} | |
event AccountCreated(RelationshipManager newAccount, address newUser, uint256 timestamp, AccountType accountType); | |
modifier onlyFirstTime(address _ownerAddress){ | |
// Ensure this is the first time the IDENTITY_TOKEN is created for user | |
require(s_relationshipContractDetails[_ownerAddress].status != true, "AccountsFactory: Account Exists"); | |
_; | |
} | |
modifier onlyAdmin(){ | |
require(s_admin == msg.sender, "AccountsFactory: Not admin"); | |
_; | |
} | |
constructor(uint256 _initialRelationshipQuantity) { | |
s_admin = msg.sender; | |
// TODO: Setup merkle drop here | |
s_initialRelationshipQuantity = _initialRelationshipQuantity; | |
} | |
function createAccount() external onlyFirstTime(msg.sender) returns(RelationshipManager _newAccount) { | |
// Only Airdropped users can createAccount | |
// Use merkle proof for airdrop | |
require( | |
// _merkleProof == | |
true, | |
"AccountsFactory: Invalid Airdrop Recipient" | |
); | |
s_relationshipContractDetails[msg.sender].status = true; | |
_newAccount = new RelationshipManager(s_initialRelationshipQuantity, msg.sender); | |
s_relationshipContractDetails[msg.sender].contractAddress = address(_newAccount); | |
emit AccountCreated(_newAccount, msg.sender, block.timestamp, AccountType.AIRDROPPED); | |
} | |
function createAccount(address _relationTokenAddress) external onlyFirstTime(msg.sender) returns(RelationshipManager _newAccount) { | |
// Users with a relationship token can create account | |
require( | |
IERC1155(_relationTokenAddress).balanceOf(msg.sender, RELATIONSHIP_TOKEN) > 0, | |
"AccountsFactory: No relationship token found" | |
); | |
s_relationshipContractDetails[msg.sender].status = true; | |
_newAccount = new RelationshipManager(s_initialRelationshipQuantity, msg.sender); | |
s_relationshipContractDetails[msg.sender].contractAddress = address(_newAccount); | |
emit AccountCreated(_newAccount, msg.sender, block.timestamp, AccountType.LINKED); | |
} | |
function updateInitialConnectQuantity(uint256 _initialRelationshipQuantity) external onlyAdmin { | |
s_initialRelationshipQuantity = _initialRelationshipQuantity; | |
} | |
function increaseUsersMinAmount(address _userAddress, uint256 _quantityAdded) external onlyAdmin { | |
// Get account details | |
address _relationContractAddress = s_relationshipContractDetails[_userAddress].contractAddress; | |
RelationshipManager(_relationContractAddress).increaseUsersMinAmount(_userAddress, _quantityAdded); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: Unlicensed | |
pragma solidity 0.8.15; | |
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; | |
import "@openzeppelin/contracts/access/AccessControl.sol"; | |
contract RelationshipManager is ERC1155{ | |
/* | |
* Set up two tokens | |
* one can only be minted once | |
* The other can be minted an unlimited number of times | |
* But, it can only be minted 99 times and then more can be minted later | |
* More can be purchased later | |
* I think we should deploy new contracts for each user and then call those contracts method from here, | |
that way events and state changes can easily be managed | |
* PROBLEMS - WITH PREVIOUS IMPLEMENTATION | |
* - Transferring relationship token increases quantity of connections token | |
*/ | |
uint256 public constant IDENTITY_TOKEN = 1; | |
uint256 public constant RELATIONSHIP_TOKEN = 2; | |
uint256 public s_initialRelationshipTokenQuantity; | |
address public s_owner; | |
address public s_admin; | |
modifier onlyOwner(address _caller){ | |
require(_caller == s_owner, "RelationshipManager: Invalid caller"); | |
_; | |
} | |
mapping(address => userRecord) public s_addressToUserRecord; | |
struct userRecord { | |
bool identityTokenMinted; | |
uint256 relationShipTokenQuantityMinted; | |
uint256 maxRelationshipQuantity; | |
} | |
event FriendLinked(address indexed accountOwner, address indexed connection, uint256 timeStamp); | |
event FriendUnLinked(address indexed accountOwner, address indexed connection, uint256 timeStamp); | |
constructor(uint256 _initialRelationshipTokenQuantity, address _owner) ERC1155("https://link.to/metadata/{id}.json"){ | |
s_owner = _owner; | |
s_initialRelationshipTokenQuantity = _initialRelationshipTokenQuantity; | |
s_addressToUserRecord[_owner].identityTokenMinted = true; | |
s_addressToUserRecord[_owner].relationShipTokenQuantityMinted += _initialRelationshipTokenQuantity; | |
s_addressToUserRecord[_owner].maxRelationshipQuantity += _initialRelationshipTokenQuantity; | |
// IDENTITY_TOKEN: Single token that represents user (Only 1 is mintable) | |
_mint(_owner, IDENTITY_TOKEN, 1, ""); | |
// RELATIONSHIP_TOKEN: Multiple token that can be distributed to friends | |
_mint(_owner, RELATIONSHIP_TOKEN, _initialRelationshipTokenQuantity, ""); | |
} | |
function linkFriend(address _friend) external onlyOwner(msg.sender) { | |
require(balanceOf(_friend, RELATIONSHIP_TOKEN) <= 0, "RelationshipManager: Connection Exists"); | |
// Update user record | |
s_addressToUserRecord[msg.sender].relationShipTokenQuantityMinted -= 1; | |
// Transfer relationship token to others | |
_safeTransferFrom(msg.sender, _friend, RELATIONSHIP_TOKEN, 1, ""); | |
emit FriendLinked(msg.sender, _friend, block.timestamp); | |
} | |
function linkFriends(address[] calldata _friends) onlyOwner(msg.sender) external { | |
// Limit bulk link to 50 to avoid infinite loop | |
require(_friends.length <= 50, "RelationshipManager: Bulk link maxed at 50"); | |
// Balance should be greater than _frends length | |
require(balanceOf(msg.sender, RELATIONSHIP_TOKEN) >= _friends.length, "RelationshipManager: Insufficient RELATIONSHIP_TOKEN balance"); | |
// Transfer relationship token to others in bulk | |
for(uint256 ii = 0; ii < _friends.length; ++ii){ | |
require(balanceOf(_friends[ii], RELATIONSHIP_TOKEN) <= 0, "RelationshipManager: Connection Exists"); | |
// Update user record | |
s_addressToUserRecord[msg.sender].relationShipTokenQuantityMinted -= 1; | |
// Transfer relationship token to others | |
_safeTransferFrom(msg.sender, _friends[ii], RELATIONSHIP_TOKEN, 1, ""); | |
emit FriendLinked(msg.sender, _friends[ii], block.timestamp); | |
} | |
} | |
function unlinkFriend(address _friend) onlyOwner(msg.sender) external { | |
// Take back the transfered token | |
_burn(_friend, RELATIONSHIP_TOKEN, 1); | |
_mint(msg.sender, RELATIONSHIP_TOKEN, 1, ""); | |
emit FriendUnLinked(msg.sender, _friend, block.timestamp); | |
} | |
function mintExtra(uint256 _additionalQuantity) external onlyOwner(msg.sender) { | |
require( | |
s_addressToUserRecord[msg.sender].relationShipTokenQuantityMinted + _additionalQuantity | |
<= s_addressToUserRecord[msg.sender].maxRelationshipQuantity, | |
"RelationshipManager: Relationship mint maxed" | |
); | |
s_addressToUserRecord[msg.sender].relationShipTokenQuantityMinted += _additionalQuantity; | |
_mint(msg.sender, RELATIONSHIP_TOKEN, _additionalQuantity, ""); | |
} | |
function getRelationship(address _tokenAddress, address _userAddress) external view returns(bool) { | |
// TODO: Ensure _tokenAddress is a contract and _userAddress is not | |
if(IERC1155(_tokenAddress).balanceOf(_userAddress, 2) >= 1){ | |
return true; | |
}else{ | |
return false; | |
} | |
} | |
function increaseUsersMinAmount(address _userAddress, uint256 _quantityAdded) external { | |
// Only admin can call contract | |
s_addressToUserRecord[_userAddress].maxRelationshipQuantity += _quantityAdded; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment