Skip to content

Commit 3e8d977

Browse files
committed
Updated the contract
1 parent d53abda commit 3e8d977

File tree

3 files changed

+120
-24
lines changed

3 files changed

+120
-24
lines changed

contracts/SuperconductorX.sol

+83-19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.18;
2+
pragma solidity ^0.8.21;
33

44
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
55
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
66
import "@openzeppelin/contracts/access/Ownable.sol";
7+
import "@openzeppelin/contracts/utils/math/Math.sol";
78

89
contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
910
// Maximum token cap
@@ -27,6 +28,7 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
2728
uint256 lastActionBlock;
2829
}
2930
mapping(address => UserState) public userStates;
31+
3032
// Events for creating entanglement
3133
event EntanglementRequested(
3234
address indexed requester,
@@ -64,9 +66,16 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
6466
uint256 amount
6567
);
6668

67-
// For community minting of SCX
68-
uint256 public constant SCX_PRICE_IN_ETH = 5e12; // 0.000005 ETH
69-
uint256 public soldSCXTokens = 0;
69+
// Tier system for community minting of SCX
70+
struct Tier {
71+
uint256 tokenCap;
72+
uint256 tokensSold;
73+
uint256 priceInETH;
74+
}
75+
Tier[] public tiers;
76+
uint256 public currentTier;
77+
mapping(uint256 => mapping(address => uint256)) public tierParticipants;
78+
mapping(uint256 => address[]) public tierParticipantAddresses;
7079

7180
// Events for community minting of SCX
7281
event CommunityMint(
@@ -86,15 +95,25 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
8695

8796
constructor() ERC20("SuperconductorX", "SCX") {
8897
_mint(msg.sender, 100000000 * 10 ** decimals()); // 100 million initial supply
98+
tiers.push(Tier(25000000e18, 0, 5e12)); // Tier 1: 25 million at 0.000005 ETH
8999
}
90100

91101
// Applying an external force, similar to applying a magnetic field on a superconductor.
92102
// A user's energy and temperature levels are adjusted based on the days elapsed since their last interaction.
93103
function applyMagneticField() public {
104+
require(balanceOf(msg.sender) > 1000e18, "Insufficient SCX");
105+
require(
106+
userStates[msg.sender].lastActionBlock != 0,
107+
"Interact with the contract first"
108+
);
109+
94110
uint256 daysElapsed = (block.number -
95111
userStates[msg.sender].lastActionBlock) / NUM_BLOCKS_DAY;
96112
if (daysElapsed > 0) {
97-
uint256 totalDaysReward = daysElapsed;
113+
uint256 baseReward = daysElapsed;
114+
uint256 tokenMultiplier = Math.sqrt(balanceOf(msg.sender) / 1e18);
115+
uint256 totalDaysReward = baseReward * tokenMultiplier;
116+
98117
userStates[msg.sender].energyLevel += totalDaysReward;
99118
userStates[msg.sender].temperature = userStates[msg.sender]
100119
.temperature < totalDaysReward
@@ -115,7 +134,7 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
115134
// Requesting entanglement mimics quantum entanglement in superconductors.
116135
// By becoming entangled, the users' energy decreases and temperature increases.
117136
function requestEntanglement(address pair) public {
118-
require(pair != msg.sender, "Cannot entangle with oneself");
137+
require(pair != msg.sender, "Cannot entangle self");
119138
userStates[msg.sender].entanglementRequest = pair;
120139
userStates[msg.sender].energyLevel = userStates[msg.sender]
121140
.energyLevel < UNIVERSAL_CONSTANT_ENERGY
@@ -136,7 +155,7 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
136155
function acceptEntanglement(address requester) public {
137156
require(
138157
userStates[requester].entanglementRequest == msg.sender,
139-
"No entanglement request from this address"
158+
"No request"
140159
);
141160
userStates[requester].entangledPair = msg.sender;
142161
userStates[msg.sender].entangledPair = requester;
@@ -205,7 +224,7 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
205224
}
206225

207226
// Represents quantum tunneling. Tokens are locked and then either successfully transferred or returned based on a probabilistic outcome.
208-
function quantumTunnelTransfer(
227+
function initiateQuantumTunnel(
209228
address to,
210229
uint256 amount
211230
) external nonReentrant {
@@ -233,7 +252,7 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
233252
// Represents the execution of a quantum tunneling event in the contract.
234253
// A tunnel is initiated by a user, and this function determines whether the tunneling is successful or not.
235254
// If users are entangled, the probability of success increases, mirroring the probabilistic nature of quantum mechanics.
236-
function executeTunnel() external nonReentrant {
255+
function completeQuantumTunnel() external nonReentrant {
237256
require(
238257
tunnelTargetBlock[msg.sender] > 0,
239258
"No tunnel initiated by this user"
@@ -346,22 +365,67 @@ contract SuperconductorX is ERC20, ReentrancyGuard, Ownable {
346365

347366
// Users can mint tokens in exchange for ETH.
348367
function communityMint() external payable nonReentrant {
349-
uint256 amountToMint = (msg.value / SCX_PRICE_IN_ETH) *
350-
10 ** decimals();
351-
require(amountToMint > 0, "Not enough ETH sent");
352-
require(
353-
balanceOf(address(this)) >= amountToMint,
354-
"The contract doesn't have enough SCX to be minted. Please try minting by sending a lower amount of ETH."
368+
require(currentTier < tiers.length, "All tiers are exhausted");
369+
370+
Tier storage tier = tiers[currentTier];
371+
372+
uint256 maxTokensAvailable = Math.min(
373+
balanceOf(address(this)),
374+
tier.tokenCap - tier.tokensSold
355375
);
376+
377+
uint256 amountToMint = (msg.value / tier.priceInETH) * 10 ** decimals();
378+
if (amountToMint > maxTokensAvailable) {
379+
amountToMint = maxTokensAvailable;
380+
}
381+
356382
require(
357-
soldSCXTokens + amountToMint <= 75000000 * 10 ** decimals(),
358-
"Exceeds available SCX tokens for community minting"
383+
amountToMint > 0,
384+
"Not enough ETH sent or no tokens available for minting"
359385
);
360386

361-
soldSCXTokens += amountToMint;
387+
uint256 ethRequired = (amountToMint * tier.priceInETH) /
388+
10 ** decimals();
389+
uint256 ethToRefund = msg.value - ethRequired;
390+
391+
tier.tokensSold += amountToMint;
362392
_transfer(address(this), msg.sender, amountToMint);
363393

364-
emit CommunityMint(msg.sender, amountToMint, msg.value);
394+
// Record the participant's purchase
395+
if (tierParticipants[currentTier][msg.sender] == 0) {
396+
tierParticipantAddresses[currentTier].push(msg.sender);
397+
}
398+
tierParticipants[currentTier][msg.sender] += amountToMint;
399+
400+
if (ethToRefund > 0) {
401+
payable(msg.sender).transfer(ethToRefund);
402+
}
403+
404+
// Move to the next tier if the current tier is exhausted
405+
if (tier.tokensSold == tier.tokenCap) {
406+
currentTier++;
407+
}
408+
409+
emit CommunityMint(msg.sender, amountToMint, ethRequired);
410+
}
411+
412+
// Get the number of participants in a specific tier
413+
function getTierParticipantCount(
414+
uint256 tierIndex
415+
) external view returns (uint256) {
416+
return tierParticipantAddresses[tierIndex].length;
417+
}
418+
419+
// Get the participant address and their purchase amount for a specific tier and index
420+
function getTierParticipant(
421+
uint256 tierIndex,
422+
uint256 participantIndex
423+
) external view returns (address, uint256) {
424+
address participant = tierParticipantAddresses[tierIndex][
425+
participantIndex
426+
];
427+
uint256 amount = tierParticipants[tierIndex][participant];
428+
return (participant, amount);
365429
}
366430

367431
// Contract owner can withdraw all the SCX tokens.

hardhat.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module.exports = {
1313
}
1414
},
1515
{
16-
version: '0.8.18',
16+
version: '0.8.21',
1717
settings: {
1818
optimizer: {
1919
enabled: true

test/SuperconductorX.js

+36-4
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,48 @@ describe('SuperconductorX', function () {
8282
})
8383

8484
describe('applyMagneticField', function () {
85-
it('Should adjust energy and temperature based on days elapsed', async function () {
85+
it('Should fail because the user needs to interact with the contract first', async function () {
8686
const { superconductorX, owner } = await loadFixture(deployFixture)
8787

8888
// Instantly mine 5761 blocks(1 day = 1 energy gained)
8989
await ethers.provider.send('hardhat_mine', ['0x1681'])
90-
await superconductorX.applyMagneticField()
90+
await expect(superconductorX.applyMagneticField()).to.be.revertedWith(
91+
'Interact with the contract first'
92+
)
93+
})
9194

92-
const userState = await superconductorX.getUserState(owner.address)
95+
it('Need to hold at least 1000 SCX before calling this function', async function () {
96+
const { superconductorX, owner, addr1 } = await loadFixture(deployFixture)
97+
98+
// Get some SCX from owner first
99+
await superconductorX.transfer(addr1.address, 1)
100+
101+
// Interact with the contract before calling this function
102+
await superconductorX.connect(addr1).transfer(owner.address, 1)
103+
104+
// Instantly mine 5761 blocks(1 day = 1 energy gained)
105+
await ethers.provider.send('hardhat_mine', ['0x1681'])
106+
await expect(
107+
superconductorX.connect(addr1).applyMagneticField()
108+
).to.be.revertedWith('Insufficient SCX')
109+
})
110+
111+
it('Should adjust energy and temperature based on days elapsed', async function () {
112+
const { superconductorX, owner, addr1 } = await loadFixture(deployFixture)
113+
114+
// Get some SCX from owner first
115+
await superconductorX.transfer(addr1.address, 1001e18)
116+
117+
// Interact with the contract before calling this function
118+
await superconductorX.connect(addr1).transfer(owner.address, 1001e18)
119+
120+
// Instantly mine 5761 blocks(1 day = 1 energy gained)
121+
await ethers.provider.send('hardhat_mine', ['0x1681'])
122+
await superconductorX.connect(addr1).applyMagneticField()
123+
124+
const userState = await superconductorX.getUserState(addr1.address)
93125

94-
expect(userState.energyLevel).to.equal(1)
126+
expect(userState.energyLevel).to.equal(100)
95127
expect(userState.temperature).to.equal(0)
96128
})
97129
})

0 commit comments

Comments
 (0)