Commit 299092d8 authored by Kegan's avatar Kegan
Browse files

deployed SteamIDToEthereum.sol to arbitrum mainnet

parent f63473fd
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
/**
* SteamID To Ethereum Translation Contract
* ----------------------------------------
* Users can link their SteamID to their ETH wallet here, allowing apps to find their Ethereum wallet on chain.
*
* Creator: Kegan 'Lystic' Hollern
* Date: September 11th 2021
*/
contract SteamIDToEthereum is Context {
using Address for address;
// mapping from HASH( SteamID ) to list of linked ETH wallets
mapping(uint256 => mapping(uint256 => address)) private _linkedWallets;
// mapping from HASH( SteamID ) to the length of the _linkedWallets internal mapping
mapping(uint256 => uint256) private _linkedWalletsIndex;
// mapping from ETH account to HASH( SteamID )
mapping(address => uint256) private _accountLinks;
/**
* Internal method to add account links
*/
function _addAccountLink(uint256 hashed_steamid64, address account) private {
require(hashed_steamid64 > 0, "invalid steamid64");
require(account != address(0x0), "invalid account");
require(!hasLink(account), "Account already linked to a SteamID!");
//link a new account
uint256 index = getNumberOfLinks(hashed_steamid64);
_linkedWallets[hashed_steamid64][index] = account; //set value
_linkedWalletsIndex[hashed_steamid64]++; //increment index
_accountLinks[account] = hashed_steamid64;
}
/**
* Internal method to remove account links
*/
function _removeAccountLink(uint256 hashed_steamid64, address account) private {
require(hashed_steamid64 > 0, "invalid steamid64");
require(account != address(0x0), "invalid account");
require(isLinked(hashed_steamid64, account), "Account not linked to the provided SteamID!");
uint256 count = getNumberOfLinks(hashed_steamid64);
assert(count > 0);
for(uint256 i = 0; i < count; i++)
{
if(_linkedWallets[hashed_steamid64][i] == account)
{
if(i != count-1)
{
// move last link into the deleted link index
// only do this if i != count-1
_linkedWallets[hashed_steamid64][i] = _linkedWallets[hashed_steamid64][count-1];
}
delete _linkedWallets[hashed_steamid64][count-1]; // delete count-1
_linkedWalletsIndex[hashed_steamid64]--; // decrement count
delete _accountLinks[account]; //delete account link
return; // can only remove one link per call (only one can exist anyways)
}
}
}
/**
* Hash a steamid64 into a format intended for use in this contract
*/
function HashSteamID(uint64 steamid64) public pure returns(uint256) {
require(steamid64 > 0, "invalid steamid64");
return uint256(keccak256(abi.encodePacked("created by kegan hollern", steamid64)));
}
/**
* Add a SteamID link
*/
function LinkSteamID(uint256 hashed_steamid64) public {
require(hashed_steamid64 > 0, "invalid steamid64");
require(!_msgSender().isContract(), "Contracts cannot link Steam Accounts!");
_addAccountLink(hashed_steamid64, _msgSender());
}
/**
* Remove the existing steamid link for sender
*/
function Unlink() public {
require(!_msgSender().isContract(), "Contracts cannot unlink Steam Accounts!");
require(hasLink(_msgSender()), "Not linked");
_removeAccountLink(getLink(_msgSender()), _msgSender());
}
/**
* Get the number of addresses linked to the steamid hash
*/
function getNumberOfLinks(uint256 hashed_steamid64) public view returns(uint256) {
require(hashed_steamid64 > 0, "invalid steamid64");
return _linkedWalletsIndex[hashed_steamid64];
}
/**
* Get the address linked to the provided steamid hash by index
*/
function getLinkByIndex(uint256 hashed_steamid64, uint256 index) public view returns(address) {
require(hashed_steamid64 > 0, "invalid steamid64");
require(index < getNumberOfLinks(hashed_steamid64), "index out of bounds");
return _linkedWallets[hashed_steamid64][index];
}
/**
* Get the steamid hash linked to the provided account
*/
function getLink(address account) public view returns(uint256) {
require(account != address(0x0), "invalid account");
return _accountLinks[account];
}
/**
* Checks if the provided steamid hash has a link to the provided account
*/
function isLinked(uint256 hashed_steamid64, address account) public view returns(bool) {
require(hashed_steamid64 > 0, "invalid steamid64");
require(account != address(0x0), "invalid account");
return _accountLinks[account] == hashed_steamid64;
}
/**
* Checks if the provided account is linked to a steamid
*/
function hasLink(address account) public view returns(bool) {
require(account != address(0x0), "invalid account");
return _accountLinks[account] != 0;
}
// don't allow any ETH payments to this contract
fallback() external payable {
revert();
}
receive() external payable {
revert();
}
}
\ No newline at end of file
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
contract SteamToEther is Context {
using Address for address;
mapping(uint64 => address[]) internal steamIdToEther;
mapping(address => uint64) internal etherToSteamID;
event AccountLinked(address _wallet, uint64 _steamId64);
event AccountUnlinked(address _wallet, uint64 _steamId64);
constructor() {
console.log("Deployed SteamToEtherContract!");
}
function GetSteamAccount(address _addr) public view returns(uint64) {
require(_addr != address(0x0), "Cannot use 0x0 address!");
return etherToSteamID[_addr];
}
function GetEthereumWallets(uint64 _steamId) public view returns (address[] memory) {
require(_steamId > 0, "Cannot have 0 for steamid!");
return steamIdToEther[_steamId];
}
function UnleakSteamAccount(uint64 _steamId64) public {
//TODO: unlink the provided steam account from our sender
}
function LinkSteamAccount(uint64 _steamId64) public {
address sender = _msgSender();
require(!sender.isContract(),"Contacts cannot link steam accounts!");
require(_steamId64 > 0, "Cannot have 0 for steam id!");
console.log("Linking steam account....");
//remove eth wallet from previous steamid association
uint64 old_steamid = etherToSteamID[sender];
if(old_steamid > 0)
{
for(uint256 i = 0; i < steamIdToEther[old_steamid].length; i++)
{
if(steamIdToEther[old_steamid][i] == sender)
{
steamIdToEther[old_steamid][i] = steamIdToEther[old_steamid][steamIdToEther[old_steamid].length-1]; //move last element into the position of our item we want to remove
steamIdToEther[old_steamid].pop(); //delete last item which is now a duplicate
}
}
}
//update eth->steamid list
etherToSteamID[sender] = _steamId64;
//if steamid->eth list does not already contain our sender then add
bool exists = false;
for(uint256 i = 0; i < steamIdToEther[_steamId64].length; i++)
{
if(steamIdToEther[_steamId64][i] == sender)
{
exists = true;
break;
}
}
if(!exists)
{
steamIdToEther[_steamId64].push(sender);
}
console.log("Account linked!");
emit AccountLinked(sender, _steamId64);
}
}
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
// this is a way to store steam/eth wallet links without exposing what wallet is linked to what steam account
contract SteamToEtherSafe is Context {
using Address for address;
mapping(uint256 => uint256) internal _links; // HASH( ETH_WALLET ) => HASH( STEAMID )
event AccountLinked(uint256 account_hash);
constructor() {
console.log("Deployed SteamToEtherSafe Contract!");
}
//verify a eth wallet is a specific steam user
function Verify(uint256 hashed_steamid, address eth_wallet) public view returns(bool) {
require(hashed_steamid > 0, "invalid steamid hash");
require(eth_wallet != address(0x0), "invalid address");
uint256 _wallet = HASH(eth_wallet);
return VerifyHashed(hashed_steamid, _wallet);
}
function VerifyHashed(uint256 hashed_steamid, uint256 hashed_eth_wallet) public view returns(bool) {
require(hashed_steamid > 0, "invalid steamid hash");
require(hashed_eth_wallet != 0, "invalid wallet hash");
return _links[hashed_eth_wallet] == hashed_steamid;
}
function DoIHaveAnAccount() public view returns(bool) {
require(!_msgSender().isContract(), "contract cannot have an account");
return HasAccount(_msgSender());
}
function HasAccount(address eth_wallet) public view returns(bool) {
require(eth_wallet != address(0x0), "invalid address");
uint256 _wallet = HASH(eth_wallet);
return HasAccountHashed(_wallet);
}
function HasAccountHashed(uint256 hashed_eth_wallet) public view returns(bool) {
require(hashed_eth_wallet != 0, "invalid wallet hash");
return _links[hashed_eth_wallet] != 0;
}
//hash should be precalculated using: https://web3js.readthedocs.io/en/v1.2.4/web3-utils.html#soliditysha3
function LinkAccount(uint256 hashed_steamid) public {
require(!_msgSender().isContract(), "cannot link account as a contract");
uint256 _wallet = HASH(_msgSender());
_links[_wallet] = hashed_steamid;
emit AccountLinked(hashed_steamid);
}
//unsafe (exposes steamid64) (should not be used! hashes should be precalculated!)
function LinkAccountUnsafe(uint64 steamid64) public {
uint256 hashed_steamid = HASH(steamid64);
LinkAccount(hashed_steamid);
}
function VerifyUnsafe(uint64 steamid64, address eth_wallet) public view returns(bool) {
require(steamid64 > 0, "invalid steamid64");
require(eth_wallet != address(0x0), "invalid address");
uint256 hashed_steamid = HASH(steamid64);
return Verify(hashed_steamid, eth_wallet);
}
// hash steamid and wallet
function HASH(address value) internal pure returns(uint256) {
return uint256(keccak256(abi.encodePacked(value)));
}
function HASH(uint64 value) internal pure returns(uint256) {
return uint256(keccak256(abi.encodePacked(value)));
}
}
\ No newline at end of file
......@@ -20,13 +20,12 @@ task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
defaultNetwork: "hardhat",
defaultNetwork: "arbitrum_mainnet",
networks: {
hardhat: {
},
arbitrum_testnet: {
url: 'https://rinkeby.arbitrum.io/rpc',
gasPrice: 0,
accounts: [secrets.testnet_privkey],
},
arbitrum_mainnet: {
......
......@@ -14,12 +14,11 @@ async function main() {
// await hre.run('compile');
// We get the contract to deploy
const SteamToEther = await hre.ethers.getContractFactory("SteamToEther");
const ste = await SteamToEther.deploy();
const SteamIDToEthereum = await ethers.getContractFactory("SteamIDToEthereum");
const ste = await SteamIDToEthereum.deploy();
await ste.deployed();
console.log("Greeter deployed to:", ste.address);
console.log("SteamIDToEthereum deployed to:", ste.address);
}
// We recommend this pattern to be able to use async/await everywhere
......
......@@ -2,6 +2,7 @@ const { expect } = require("chai");
const { BigNumber } = require("ethers");
const { ethers } = require("hardhat");
/*
describe("SkinZNFT", function() {
it("can deploy successfully", async function() {
const skznft = await hre.ethers.getContractFactory("SkinZNFT");
......@@ -38,13 +39,68 @@ describe("SkinZNFT", function() {
});
});
*/
/*
describe("SteamToEther", function () {
it("Created valid link. Test link values exist", async function () {
const SteamToEther = await ethers.getContractFactory("SteamToEther");
const ste = await SteamToEther.deploy();
describe("SteamIDToEthereum", function () {
it("Create a valid link, test it, unlink, test it.", async function () {
const SteamIDToEthereum = await ethers.getContractFactory("SteamIDToEthereum");
const ste = await SteamIDToEthereum.deploy();
await ste.deployed();
//basically we do th
console.log(ethers.utils.solidityPack(["string","uint64"], ["created by kegan hollern","12345671234567890"]));
let steamid_hash = ethers.utils.solidityKeccak256(["string","uint64"], ["created by kegan hollern","12345671234567890"]);
let steamid_hash2 = ethers.utils.solidityKeccak256(["string","uint64"], ["created by kegan hollern","12345671234567891"]);
console.log('testing hashing alg');
expect(await ste.HashSteamID("12345671234567890")).to.equal(steamid_hash);
console.log('testing accessors');
expect(await ste.getNumberOfLinks(steamid_hash)).to.equal(0);
await expect(ste.getLinkByIndex(steamid_hash, 0)).to.be.reverted; //expecting an index out of bounds revert
expect(await ste.getLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal("0");
expect(await ste.isLinked(steamid_hash, "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(false);
expect(await ste.hasLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(false);
console.log('linking account');
await ste.LinkSteamID(steamid_hash);
console.log('testing accessors');
expect(await ste.getNumberOfLinks(steamid_hash)).to.equal(1);
expect(await ste.getLinkByIndex(steamid_hash, 0)).to.equal("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
expect(await ste.getLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(steamid_hash);
expect(await ste.isLinked(steamid_hash, "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(true);
expect(await ste.hasLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(true);
console.log('trying to relink');
await expect(ste.LinkSteamID(steamid_hash2)).to.be.reverted;
console.log('unlinking');
await ste.Unlink();
await expect(ste.Unlink()).to.be.reverted;
console.log('testing accessors');
expect(await ste.getNumberOfLinks(steamid_hash)).to.equal(0);
await expect(ste.getLinkByIndex(steamid_hash, 0)).to.be.reverted; //expecting an index out of bounds revert
expect(await ste.getLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal("0");
expect(await ste.isLinked(steamid_hash, "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(false);
expect(await ste.hasLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(false);
console.log('relinking');
await ste.LinkSteamID(steamid_hash2);
console.log('testing accessors');
expect(await ste.getNumberOfLinks(steamid_hash2)).to.equal(1);
expect(await ste.getLinkByIndex(steamid_hash2, 0)).to.equal("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
expect(await ste.getLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(steamid_hash2);
expect(await ste.isLinked(steamid_hash2, "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(true);
expect(await ste.hasLink("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")).to.equal(true);
/*
console.log('linking account');
await ste.LinkSteamAccount('12345671234567890');
console.log('testing get eth wallets');
......@@ -55,8 +111,10 @@ describe("SteamToEther", function () {
expect(await ste.GetSteamAccount('0xBcd4042DE499D14e55001CcbB24a551F3b954096')).to.equal('0');
console.log('testing eth wallets');
expect(await ste.GetEthereumWallets('12345671234567891')).to.eql([]);
*/
});
});
/*
describe("SteamToEther", function() {
it("Update linked steam account. Test link values are valid", async function() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment