0xfacet / facet-scan Goto Github PK
View Code? Open in Web Editor NEWA client for the Facet Protocol. Use it to initiate contract interactions and view the results.
Home Page: https://facetscan.com
A client for the Facet Protocol. Use it to initiate contract interactions and view the results.
Home Page: https://facetscan.com
Issue Summary:
I would like to propose the implementation of a simple Snapshot Rewards Contract in Solidity.
Background:
The goal is to create a contract where users can take snapshots of their token balances and later claim rewards based on the difference between their current balance and the balance at the time of the snapshot.
Proposed Solution:
We can achieve this functionality with the following contract:
class SnapshotRewards < Contracts::ERC20
pragma :rubidity, "1.0.0"
constructor(name: :string, symbol: :string, decimals: :uint256) {
super(name, symbol, decimals)
end
# Take a snapshot of the current reward balance
function :takeSnapshot, :public, :virtual do
s.snapshotBalance[msg.sender] = s.balanceOf[msg.sender]
end
# Claim rewards based on the snapshot
function :claimReward, :public, :virtual do
snapshotBalance = s.snapshotBalance[msg.sender]
currentBalance = s.balanceOf[msg.sender]
if snapshotBalance > 0 && currentBalance > snapshotBalance
reward = currentBalance - snapshotBalance
s.snapshotBalance[msg.sender] = currentBalance
super.transfer(to: msg.sender, amount: reward)
end
end
end
Expected Result:
The contract allows users to take snapshots of their token balances and claim rewards based on the difference.
Additional Information:
This contract does not involve staking and is designed for a simple reward distribution mechanism.
Please let me know your thoughts and any feedback on this proposal.
Is there a library file like ethers.js?
import 'ethscriptions/contracts/DumbContract.sol';
import 'ethscriptions/contracts/UniswapV2Router02.sol';
class Contracts::RubidityUniswapV2Pair < Contract
address :factory
address :token0
address :token1
uint112 :reserve0
uint112 :reserve1
uint32 :blockTimestampLast
uint :price0CumulativeLast
uint :price1CumulativeLast
uint :kLast
uint :unlocked
bytes4 :SELECTOR
address :feeTo
uint :MINIMUM_LIQUIDITY
constructor(_token0: :address, _token1: :address) {
@factory = msg.sender
@token0 = _token0
@Token1 = _token1
@unlocked = 1
@selector = bytes4(keccak256(bytes('transfer(address,uint256)')))
@feeto = IUniswapV2Factory(IUniswapV2Router02.new().factory()).feeTo()
@MINIMUM_LIQUIDITY = 10**3
}
modifier onlyOwner {
require(msg.sender == @factory, 'UniswapV2: FORBIDDEN')
_;
}
modifier lock {
require(unlocked == 1, 'UniswapV2: LOCKED')
unlocked = 0
_;
unlocked = 1
}
function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
_reserve0 = reserve0
_reserve1 = reserve1
_blockTimestampLast = blockTimestampLast
}
function _safeTransfer(_token: :address, _to: :address, _value: :uint) private {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, _to, _value))
require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED')
}
function mint(_to: :address) external lock returns (uint liquidity) {
(uint112 _reserve0, uint112 _reserve1,) = getReserves()
uint balance0 = DumbContract(token0).balanceOf(address(this))
uint balance1 = DumbContract(token1).balanceOf(address(this))
uint amount0 = balance0.sub(_reserve0)
uint amount1 = balance1.sub(_reserve1)
bool feeOn = _mintFee(_reserve0, _reserve1)
uint _totalSupply = totalSupply
if (_totalSupply == 0) {
liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY)
_mint(address(0), MINIMUM_LIQUIDITY)
} else {
liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1)
}
require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED')
_mint(_to, liquidity)
_update(balance0, balance1, _reserve0, _reserve1)
if (feeOn) kLast = uint(reserve0).mul(reserve1)
}
// Other functions like burn, swap, skim, sync need to be adapted similarly.
// Make sure to handle state variables and external contract interactions correctly.
// ...
}
You would need to adapt other functions like burn, swap, skim, and sync similarly and ensure correct handling of state variables and external contract interactions.
Hello, I would like to offer support to the web3 ecosystem as a frontend developer. Before I begin development, I wanted to inquire whether there is such a need or if it is allowed.
The reason for my request is that I am currently in a job search, and I believe that the support I provide to a web3 project could serve as a reference.
Thanks.
class Contracts::ERC20Storage < ContractImplementation
string :public, :name
string :public, :symbol
uint256 :public, :decimals
uint256 :public, :totalSupply
mapping ({ addressOrDumbContract: :uint256 }), :public, :balanceOf
mapping ({ addressOrDumbContract: mapping(addressOrDumbContract: :uint256) }), :public, :allowance
end
class Contracts::ERC20Logic < ContractImplementation
is :ERC20Storage
constructor(name: :string, symbol: :string, decimals: :uint256) {
s.name = name
s.symbol = symbol
s.decimals = decimals
}
function :transfer, { to: :addressOrDumbContract, amount: :uint256 }, :public, :virtual, returns: :bool do
require(s.balanceOf[msg.sender] >= amount, 'Insufficient balance')
s.balanceOf[msg.sender] -= amount
s.balanceOf[to] += amount
emit :Transfer, from: msg.sender, to: to, amount: amount
return true
end
end
class Contracts::ERC20Proxy < ContractImplementation
is :ERC20Storage
mapping ({ addressOrDumbContract: :addressOrDumbContract }), :internal, :virtual, :logicContracts
constructor(logicContractAddress: :addressOrDumbContract) {
s.logicContracts[msg.sender] = logicContractAddress
}
function :fallback, :public do
logicContract = s.logicContracts[msg.sender]
delegateCall(logicContract, msg.data)
end
end
ERC20Storage defines the contract's storage variables.
ERC20Logic contains the contract's logic for functions like transfer. It inherits from ERC20Storage.
ERC20Proxy delegates calls to the logic contract and maintains a mapping of logic contracts for each user.
With this structure, you can deploy a new ERC20Logic contract with updated logic and then update the ERC20Proxy contract to point to the new logic contract address
import 'ethscriptions/contracts/DumbContract.sol';
class Contracts::UniswapV2ERC20 < Contract
string :name
string :symbol
uint8 :decimals
uint :totalSupply
mapping(address => uint) :balanceOf
mapping(address => mapping(address => uint)) :allowance
bytes32 :DOMAIN_SEPARATOR
bytes32 :PERMIT_TYPEHASH
mapping(address => uint) :nonces
event Approval(address indexed owner, address indexed spender, uint value)
event Transfer(address indexed from, address indexed to, uint value)
constructor() {
@name = 'Uniswap V2'
@symbol = 'UNI-V2'
@dECIMALS = 18
@totalSupply = 0
@DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
ChainId,
address(this)
)
)
@PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9
}
function mint(address to, uint value) internal {
totalSupply = totalSupply.add(value)
balanceOf[to] = balanceOf[to].add(value)
emit Transfer(address(0), to, value)
}
function burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value)
totalSupply = totalSupply.sub(value)
emit Transfer(from, address(0), value)
}
function approve(address spender, uint value) external returns (bool) {
allowance[msg.sender][spender] = value
emit Approval(msg.sender, spender, value)
return true
}
function transfer(address to, uint value) external returns (bool) {
require(balanceOf[msg.sender] >= value, 'UniswapV2: INSUFFICIENT_BALANCE')
balanceOf[msg.sender] = balanceOf[msg.sender].sub(value)
balanceOf[to] = balanceOf[to].add(value)
emit Transfer(msg.sender, to, value)
return true
}
function transferFrom(address from, address to, uint value) external returns (bool) {
require(balanceOf[from] >= value, 'UniswapV2: INSUFFICIENT_BALANCE')
require(allowance[from][msg.sender] >= value, 'UniswapV2: ALLOWANCE_EXCEEDED')
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value)
balanceOf[from] = balanceOf[from].sub(value)
balanceOf[to] = balanceOf[to].add(value)
emit Transfer(from, to, value)
return true
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, 'UniswapV2: EXPIRED')
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
)
address recoveredAddress = ecrecover(digest, v, r, s)
require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE')
allowance[owner][spender] = value
emit Approval(owner, spender, value)
}
}
Issue Description:
A potential reentrancy vulnerability exists within the smart contract code. Reentrancy vulnerabilities can allow attackers to manipulate contract state and exploit unintended behavior, potentially leading to financial losses or unauthorized access to funds. This issue report aims to highlight the situation and provide recommendations for mitigating the vulnerability.
Affected Contract:
Contracts::PublicMintERC20 and related contracts.
Details:
The codebase follows good practices for security, and at first glance, there doesn't appear to be a direct reentrancy vulnerability in the provided code. The contract seems to be handling token minting and transfers within its own functions.
Mitigation Recommendation:
To further ensure the contract's security, it's recommended to adhere to the "pull" mechanism for transferring tokens. This helps prevent potential reentrancy attacks by having external contracts initiate token transfers rather than the smart contract initiating transfers directly.
Proposed Solution:
When interacting with external contracts, ensure that the recipient (external contract) initiates the transfer of tokens or Ether.
Consider implementing a design where external contracts request funds from your contract before receiving them.
Validate the requests and ensure that the recipient contract is in a safe state to receive the funds before approving the transfer.
Preventive Measures:
Apply the checks-effects-interactions pattern to critical functions to minimize the risk of reentrancy.
Use state variables or reentrancy guards to track ongoing executions of sensitive functions.
Conduct comprehensive testing and review the code with the goal of identifying any possible reentrancy scenarios.
Recommendation Summary:
Given the current code and its structure, there isn't an immediate reentrancy vulnerability. However, to enhance the contract's security posture and minimize potential risks, it is advised to adopt the "pull" mechanism for token transfers, following the best practices outlined above.
It's essential to conduct a thorough security audit by experienced smart contract auditors to identify and address any potential vulnerabilities before deploying the contract to a production environment.
Severity:
Low/Medium
Acknowledgment:
This issue report was created to promote awareness and best practices for secure smart contract development. It is not a substitute for professional security auditing and consultation.
class Contracts::ERC20Transfer < ContractImplementation
is :ERC20Storage
function :transfer, { to: :addressOrDumbContract, amount: :uint256 }, :public do
require(s.balanceOf[msg.sender] >= amount, 'Insufficient balance')
s.balanceOf[msg.sender] -= amount
s.balanceOf[to] += amount
emit :Transfer, from: msg.sender, to: to, amount: amount
end
end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.