Skip to content

Instantly share code, notes, and snippets.

@wrightkhlebisol
Created August 17, 2022 17:34
Show Gist options
  • Save wrightkhlebisol/c0244c61a3385fbee5e558da0942af0f to your computer and use it in GitHub Desktop.
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=
// 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);
}
}
// 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