-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
:wq :
- Loading branch information
Showing
8 changed files
with
9,849 additions
and
4,437 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import "./PlayerHandle.sol"; | ||
|
||
contract MockENSResolver is IENSResolver { | ||
mapping(bytes32 => string) public names; | ||
|
||
function setName(bytes32 node, string memory name) public { | ||
names[node] = name; | ||
} | ||
|
||
function name(bytes32 node) external view override returns (string memory) { | ||
return names[node]; | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; | ||
|
||
interface IENSResolver { | ||
function name(bytes32 node) external view returns (string memory); | ||
} | ||
|
||
error InvalidHandle(); | ||
error HandleAlreadyTaken(); | ||
error PlayerNotEligible(); | ||
|
||
contract PlayerHandle is Ownable { | ||
using Strings for uint256; | ||
|
||
IENSResolver public ensResolver; | ||
mapping(address => string) private handles; | ||
mapping(string => address) private handleOwners; | ||
mapping(address => bool) private useEns; | ||
|
||
event HandleRegistered(address indexed player, string handle); | ||
event HandleChanged(address indexed player, string newHandle); | ||
event UseEnsSet(address indexed player, bool useEns); | ||
|
||
constructor(address _ensResolver) { | ||
ensResolver = IENSResolver(_ensResolver); | ||
} | ||
|
||
function registerHandle(string memory handle) external { | ||
if (!checkHandleValidity(handle)) { | ||
revert InvalidHandle(); | ||
} | ||
if (handleOwners[handle] != address(0)) { | ||
revert HandleAlreadyTaken(); | ||
} | ||
if (!checkPlayerEligibility(msg.sender)) { | ||
revert PlayerNotEligible(); | ||
} | ||
|
||
if (bytes(handles[msg.sender]).length > 0) { | ||
handleOwners[handles[msg.sender]] = address(0); | ||
} | ||
|
||
handles[msg.sender] = handle; | ||
handleOwners[handle] = msg.sender; | ||
|
||
emit HandleRegistered(msg.sender, handle); | ||
} | ||
|
||
function changeHandle(string memory newHandle) external { | ||
if (!checkHandleValidity(newHandle)) { | ||
revert InvalidHandle(); | ||
} | ||
|
||
if (handleOwners[newHandle] != address(0)) { | ||
revert HandleAlreadyTaken(); | ||
} | ||
|
||
string memory oldHandle = handles[msg.sender]; | ||
handles[msg.sender] = newHandle; | ||
handleOwners[newHandle] = msg.sender; | ||
handleOwners[oldHandle] = address(0); | ||
|
||
emit HandleChanged(msg.sender, newHandle); | ||
} | ||
|
||
function setUseEns(bool _useEns) external { | ||
useEns[msg.sender] = _useEns; | ||
emit UseEnsSet(msg.sender, _useEns); | ||
} | ||
|
||
function getPlayerHandle(address player) external view returns (string memory) { | ||
if (useEns[player]) { | ||
bytes32 node = keccak256(abi.encodePacked(addressToBytes32(player))); | ||
string memory ensName = ensResolver.name(node); | ||
if (bytes(ensName).length > 0) { | ||
return ensName; | ||
} | ||
} | ||
return handles[player]; | ||
} | ||
|
||
function checkHandleValidity(string memory handle) public pure returns (bool) { | ||
bytes memory b = bytes(handle); | ||
if (b.length < 5 || b.length > 15) { | ||
return false; | ||
} | ||
for (uint256 i; i < b.length; i++) { | ||
bytes1 char = b[i]; | ||
if (!(char >= 0x30 && char <= 0x39) && !(char >= 0x41 && char <= 0x5A) && !(char >= 0x61 && char <= 0x7A)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
function checkPlayerEligibility(address player) public pure returns (bool) { | ||
return true; // Placeholder function; implement eligibility logic as needed | ||
} | ||
|
||
function addressToBytes32(address addr) private pure returns (bytes32) { | ||
return bytes32(uint256(uint160(addr))); | ||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import "forge-std/Test.sol"; | ||
import "../PlayerHandle.sol"; | ||
import {MockENSResolver} from "../MockResolver.sol"; | ||
|
||
// running tests for PlayerHandle and MockENSResolver | ||
contract PlayerHandleTest is Test { | ||
PlayerHandle public playerHandle; | ||
MockENSResolver public mockENSResolver; | ||
|
||
address public alice = address(0x1); | ||
address public bob = address(0x2); | ||
|
||
function setUp() public { | ||
mockENSResolver = new MockENSResolver(); | ||
playerHandle = new PlayerHandle(address(mockENSResolver)); | ||
} | ||
|
||
function testRegisterHandle() public { | ||
vm.prank(alice); | ||
playerHandle.registerHandle("AliceHandle"); | ||
|
||
assertEq(playerHandle.getPlayerHandle(alice), "AliceHandle"); | ||
} | ||
|
||
function testRegisterInvalidHandle() public { | ||
vm.prank(alice); | ||
vm.expectRevert(abi.encodeWithSignature("InvalidHandle()")); | ||
playerHandle.registerHandle("a"); | ||
} | ||
|
||
function testHandleAlreadyTaken() public { | ||
vm.prank(alice); | ||
playerHandle.registerHandle("AliceHandle"); | ||
|
||
vm.prank(bob); | ||
vm.expectRevert(abi.encodeWithSignature("HandleAlreadyTaken()")); | ||
playerHandle.registerHandle("AliceHandle"); | ||
} | ||
|
||
function testChangeHandle() public { | ||
vm.prank(alice); | ||
playerHandle.registerHandle("AliceHandle"); | ||
|
||
vm.prank(alice); | ||
playerHandle.changeHandle("NewAliceHandle"); | ||
|
||
assertEq(playerHandle.getPlayerHandle(alice), "NewAliceHandle"); | ||
} | ||
|
||
function testSetUseEns() public { | ||
bytes32 node = keccak256(abi.encodePacked(addressToBytes32(alice))); | ||
mockENSResolver.setName(node, "alice.eth"); | ||
|
||
vm.prank(alice); | ||
playerHandle.setUseEns(true); | ||
|
||
assertEq(playerHandle.getPlayerHandle(alice), "alice.eth"); | ||
} | ||
|
||
function testUnsetUseEns() public { | ||
bytes32 node = keccak256(abi.encodePacked(addressToBytes32(alice))); | ||
mockENSResolver.setName(node, "alice.eth"); | ||
|
||
vm.prank(alice); | ||
playerHandle.registerHandle("AliceHandle"); | ||
playerHandle.setUseEns(true); | ||
playerHandle.setUseEns(false); | ||
|
||
assertEq(playerHandle.getPlayerHandle(alice), "AliceHandle"); | ||
} | ||
|
||
function addressToBytes32(address addr) private pure returns (bytes32) { | ||
return bytes32(uint256(uint160(addr))); | ||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { useEffect, useState } from "react" | ||
|
||
import { toast } from "sonner" | ||
|
||
function useOfflineCheck() { | ||
const [isOnline, setIsOnline] = useState(true) | ||
|
||
useEffect(() => { | ||
const handleOnline = () => setIsOnline(true) | ||
const handleOffline = () => setIsOnline(false) | ||
|
||
window.addEventListener("online", handleOnline) | ||
window.addEventListener("offline", handleOffline) | ||
|
||
return () => { | ||
window.removeEventListener("online", handleOnline) | ||
window.removeEventListener("offline", handleOffline) | ||
} | ||
}, []) | ||
|
||
useEffect(() => { | ||
if (!isOnline) { | ||
toast.error("App is offline. Please check your internet connection.", { | ||
dismissible: false, | ||
duration: Infinity, | ||
}) | ||
} else { | ||
toast.dismiss() | ||
} | ||
}, [isOnline]) | ||
} | ||
|
||
export default useOfflineCheck |
This file contains 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
Oops, something went wrong.