This nametag was submitted by Kleros Curate.
friend.tech v2.0: Best Friend
Source Code
Latest 25 from a total of 24,629 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 41208784 | 2 days ago | IN | 0 ETH | 0.00000021 | ||||
| Withdraw | 41208782 | 2 days ago | IN | 0 ETH | 0.0000002 | ||||
| Withdraw | 41208780 | 2 days ago | IN | 0 ETH | 0.00000021 | ||||
| Withdraw | 41208719 | 2 days ago | IN | 0 ETH | 0.00000023 | ||||
| Withdraw | 41208711 | 2 days ago | IN | 0 ETH | 0.00000022 | ||||
| Withdraw | 41208708 | 2 days ago | IN | 0 ETH | 0.00000027 | ||||
| Withdraw | 40965672 | 7 days ago | IN | 0 ETH | 0.00000025 | ||||
| Withdraw | 40916602 | 9 days ago | IN | 0 ETH | 0.00000032 | ||||
| Withdraw | 40904776 | 9 days ago | IN | 0 ETH | 0.00000033 | ||||
| Withdraw | 40363566 | 21 days ago | IN | 0 ETH | 0.0000002 | ||||
| Withdraw | 40363533 | 21 days ago | IN | 0 ETH | 0.0000002 | ||||
| Withdraw | 40363504 | 21 days ago | IN | 0 ETH | 0.0000003 | ||||
| Withdraw | 40346357 | 22 days ago | IN | 0 ETH | 0.00000029 | ||||
| Withdraw | 40346143 | 22 days ago | IN | 0 ETH | 0.00000044 | ||||
| Withdraw | 40228294 | 24 days ago | IN | 0 ETH | 0.00000014 | ||||
| Withdraw | 40189734 | 25 days ago | IN | 0 ETH | 0.00000016 | ||||
| Withdraw | 40159654 | 26 days ago | IN | 0 ETH | 0.00000028 | ||||
| Withdraw | 40155776 | 26 days ago | IN | 0 ETH | 0.00000011 | ||||
| Withdraw | 40148525 | 26 days ago | IN | 0 ETH | 0.00000034 | ||||
| Withdraw | 40079890 | 28 days ago | IN | 0 ETH | 0.00000008 | ||||
| Withdraw | 40038349 | 29 days ago | IN | 0 ETH | 0.00000015 | ||||
| Withdraw | 39851522 | 33 days ago | IN | 0 ETH | 0.00000015 | ||||
| Withdraw | 39767527 | 35 days ago | IN | 0 ETH | 0.00000029 | ||||
| Withdraw | 39572487 | 40 days ago | IN | 0 ETH | 0.00000021 | ||||
| Withdraw | 39544000 | 40 days ago | IN | 0 ETH | 0.0000001 |
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x2eE4f6c5...47B3234Ab The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
BestFriend
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import { Owned } from "lib/solmate/src/auth/Owned.sol";
import { IERC20 } from "src/interfaces/IERC20.sol";
import { Points } from "src/Points.sol";
import { IBestFriend } from "src/interfaces/IBestFriend.sol";
// BestFriend is a friend you can trust. He is a friend who gives you points for your
// friendship, and he is a friend who will never let you down.
//
// Note the owner is capable of manipulating of determining distribution of points.
//
// Have fun reading it. Hopefully it's bug-free. God bless.
contract BestFriend is Owned(msg.sender), IBestFriend {
// Info of each user.
struct UserInfo {
uint256 lastDepositBlock; // The last block the user deposited/withdrew LP tokens
uint256 amount; // How many LP tokens the user has provided.
uint256 rewardDebt; // Reward debt. See explanation below.
//
// We do some fancy math here. Basically, any point in time, the amount of pointss
// entitled to a user but is pending to be distributed is:
//
// pending reward = (user.amount * pool.accpointsPerShare) - user.rewardDebt
//
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
// 1. The pool's `accpointsPerShare` (and `lastRewardBlock`) gets updated.
// 2. User receives the pending reward sent to his/her address.
// 3. User's `amount` gets updated.
// 4. User's `rewardDebt` gets updated.
}
// Info of each pool.
struct PoolInfo {
IERC20 lpToken; // Address of LP token contract.
uint256 lastRewardBlock; // Last block number that pointss distribution occurs.
uint256 bonusPointsAccrued; // Total number of bonus points that have been received.
uint256 bonusPointsDistributed; // Bonus points that have been distributed so far.
uint256 accpointsPerShare; // Accumulated points per share, times wag. See below.
}
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice POINTS!!
Points public immutable points;
/// @notice Block number when the reward period ends, unless extended
uint256 public endBlock;
/// @notice The number of points distributed per block
uint256 public immutable pointsPerBlock;
/// @notice Information stored relating to the BunnySwap Pool
PoolInfo public pool;
/// @notice Mapping to keep track of stakers
mapping(address => UserInfo) public userInfo;
/// @notice Scale factor for fixed point math, with a meme makerdao name
uint256 public constant wag = 1e12;
/// @notice The address of RabbitRouter
address public immutable router;
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Deposit(address indexed user, uint256 amount);
event Withdraw(address indexed user, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 amount);
/*
* @param Points the points contract for onchain points
* @param _pool Starting data for the pool, note if this is misconfigured the contract *will* malfunction
* @param _pointsPerBlock The number of points to distribute per block
* @param _endBlock The block number at which the reward period ends
* @param _router The address of the router contract
*/
constructor(Points _points, PoolInfo memory _pool, uint256 _pointsPerBlock, uint256 _endBlock, address _router) {
points = _points;
pointsPerBlock = _pointsPerBlock;
endBlock = _endBlock;
pool = _pool;
router = _router;
}
/*
* @param newEndBlock The new end block for the new reward period
* @safety Points must be sent to BestFriend in order to fund the extended operation
*/
function extendEndBlock(uint256 newEndBlock) external onlyOwner {
endBlock = newEndBlock;
}
/*//////////////////////////////////////////////////////////////
VIEW
//////////////////////////////////////////////////////////////*/
/*
* @notice View function to see pending points on frontend.
* @param _user Address of user.
*
* @return Pending points reward for a given user.
*/
function pendingpoints(address _user) external view returns (uint256) {
UserInfo storage user = userInfo[_user];
uint256 accpointsPerShare = pool.accpointsPerShare;
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
uint256 lastEligibleBlock = block.number < endBlock ? block.number : endBlock;
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
uint256 multiplier;
if (lastEligibleBlock <= pool.lastRewardBlock) {
multiplier = 0;
} else {
multiplier = lastEligibleBlock - pool.lastRewardBlock;
}
uint256 pointsReward = multiplier * pointsPerBlock + pool.bonusPointsAccrued - pool.bonusPointsDistributed;
accpointsPerShare = accpointsPerShare + pointsReward * wag / lpSupply;
}
return user.amount * accpointsPerShare / wag - user.rewardDebt;
}
/*
* @notice Update reward variables of the given pool to be up-to-date.
*/
function updatePool() public {
if (block.number <= pool.lastRewardBlock) {
return;
}
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
if (lpSupply == 0) {
pool.lastRewardBlock = block.number;
return;
}
uint256 lastEligibleBlock = block.number < endBlock ? block.number : endBlock;
uint256 multiplier;
if (lastEligibleBlock <= pool.lastRewardBlock) {
multiplier = 0;
} else {
multiplier = lastEligibleBlock - pool.lastRewardBlock;
}
uint256 pointsReward = multiplier * pointsPerBlock + pool.bonusPointsAccrued - pool.bonusPointsDistributed;
pool.accpointsPerShare = pool.accpointsPerShare + pointsReward * wag / lpSupply;
pool.lastRewardBlock = block.number;
pool.bonusPointsDistributed = pool.bonusPointsAccrued;
}
/*
* @notice Let your best friend hold onto your LP tokens for points
* @param _amount The amount of LP tokens to deposit
* @param onBehalfOf The address to deposit the LP tokens for, should be msg.sender unless you're the router
*/
function deposit(uint256 _amount, address onBehalfOf) external {
if (onBehalfOf != msg.sender) {
require(router == msg.sender, "deposit: not authorized");
}
UserInfo storage user = userInfo[onBehalfOf];
updatePool();
if (user.amount > 0) {
uint256 pending = ((user.amount * pool.accpointsPerShare) / wag) - user.rewardDebt;
points.transfer(onBehalfOf, pending);
}
pool.lpToken.transferFrom(address(msg.sender), address(this), _amount);
user.amount = user.amount + _amount;
user.rewardDebt = user.amount * pool.accpointsPerShare / wag;
user.lastDepositBlock = block.number;
emit Deposit(onBehalfOf, _amount);
}
/*
* @notice Withdraw LP tokens from BestFriend
* @param _amount The amount of LP tokens to withdraw
* @param onBehalfOf The address to withdraw the LP tokens for, should be msg.sender unless you're the router
*/
function withdraw(uint256 _amount, address onBehalfOf) external {
if (onBehalfOf != msg.sender) {
require(router == msg.sender, "withdraw: not authorized");
}
UserInfo storage user = userInfo[onBehalfOf];
require(user.amount >= _amount, "withdraw: not good");
require(user.lastDepositBlock + 5 < block.number, "withdraw: wait");
updatePool();
uint256 pending = ((user.amount * pool.accpointsPerShare) / wag) - user.rewardDebt;
points.transfer(onBehalfOf, pending);
user.amount = user.amount - _amount;
user.rewardDebt = (user.amount * pool.accpointsPerShare) / wag;
pool.lpToken.transfer(msg.sender, _amount);
emit Withdraw(onBehalfOf, _amount);
}
/*
* @notice Lets a contract (Clubs) add to the rewards pool as a bonus
* @param _amount The amount of points to add to the bonus pool
*/
function addBonusPoints(uint256 _amount) external {
pool.bonusPointsAccrued = pool.bonusPointsAccrued + _amount;
points.transferFrom(msg.sender, address(this), _amount);
}
/*
* @notice Withdraw without collecting rewards, for emergency situations
* @note I don't think any MasterChef fork has ever needed to use this, but kept it
* as it doesn't hurt.
*/
function emergencyWithdraw() external {
UserInfo storage user = userInfo[msg.sender];
pool.lpToken.transfer(address(msg.sender), user.amount);
emit EmergencyWithdraw(msg.sender, user.amount);
user.amount = 0;
user.rewardDebt = 0;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event OwnershipTransferred(address indexed user, address indexed newOwner);
/*//////////////////////////////////////////////////////////////
OWNERSHIP STORAGE
//////////////////////////////////////////////////////////////*/
address public owner;
modifier onlyOwner() virtual {
require(msg.sender == owner, "UNAUTHORIZED");
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(address _owner) {
owner = _owner;
emit OwnershipTransferred(address(0), _owner);
}
/*//////////////////////////////////////////////////////////////
OWNERSHIP LOGIC
//////////////////////////////////////////////////////////////*/
function transferOwnership(address newOwner) public virtual onlyOwner {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}/// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}/// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import { MerkleProofLib } from "lib/solady/src/utils/MerkleProofLib.sol";
import { Owned } from "lib/solmate/src/auth/Owned.sol";
import { IPoints } from "./interfaces/IPoints.sol";
/// @title Points
/// @author CopyPaste
/// @notice A Standard Implementation of Points for FriendTechV2
contract Points is Owned(msg.sender), IPoints {
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/// Merkle Root for the point claims
bytes32 public immutable merkleRootA;
bytes32 public immutable merkleRootB;
mapping(address user => uint256 balance) public balanceOf;
mapping(address owner => mapping(address spender => uint256 amount)) public allowance;
mapping(address user => bool hasClaimedA) public claimedA;
mapping(address user => bool hasClaimedB) public claimedB;
/// The totalSupply of points
uint256 public totalSupply;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/*
* @param _merkleRootA The merkle root for first the point claims
* @param _merkleRootB The merkle root for second the point claims
*/
constructor(bytes32 _merkleRootA, bytes32 _merkleRootB) {
merkleRootA = _merkleRootA;
merkleRootB = _merkleRootB;
}
/*//////////////////////////////////////////////////////////////
METADATA
//////////////////////////////////////////////////////////////*/
string public name = "FRIEND";
string public symbol = "FRIEND";
uint8 public decimals = 18;
/*//////////////////////////////////////////////////////////////
ACCESS CONTROL
//////////////////////////////////////////////////////////////*/
mapping(address _contract => bool isWhitelisted) public isAllowed;
mapping(bytes4 functionSignature => bool canBeCalled) public isOpen;
modifier onlyWhitelisted() {
require(isAllowed[msg.sender] || isOpen[msg.sig], "WHITELIST");
_;
}
/*
* @param _contract The contract address allowed to interact with points
* @param toggle The toggle for whether or not the contract is allowed
*/
function toggleContract(address _contract, bool toggle) external onlyOwner {
isAllowed[_contract] = toggle;
}
/*
* @param function The function to open to the public
* @param toggle The toggle for whether or not the contract is allowed
*/
function toggleFunction(bytes4 functionSig, bool toggle) external onlyOwner {
isOpen[functionSig] = toggle;
}
/*
* @param to address to recieve the points
* @param amount The amount of points to mint
*/
function mint(address to, uint256 amount) external onlyOwner {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
/*//////////////////////////////////////////////////////////////
TRANSFER LOGIC
//////////////////////////////////////////////////////////////*/
/*
* @param proof The merkle proof supplied by the user to prove ownership of the claim
* @param recipient The address that will receive the claimed points
* @param amount The amount of points claimed
*/
function claimA(bytes32[] calldata proof, address recipient, uint256 amount, address[] calldata giftRecipients, uint256 giftAmount) external {
require(!claimedA[msg.sender], "Points: already claimed");
require(giftAmount <= amount, "Points: gift amount exceeds claim"); // Would underflow anyway but you can never be too safe
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender, amount))));
require(MerkleProofLib.verifyCalldata(proof, merkleRootA, leaf), "Points: invalid proof");
claimedA[msg.sender] = true;
if (giftAmount != 0) {
uint256 perUser = giftAmount / giftRecipients.length;
amount -= giftAmount;
for (uint256 i = 0; i < giftRecipients.length; ) {
balanceOf[giftRecipients[i]] += perUser;
unchecked {
++i;
}
}
}
totalSupply += amount + giftAmount;
// Mint the points to the recipient
unchecked {
balanceOf[recipient] += amount;
}
emit ClaimedA(msg.sender, recipient, amount);
}
/*
* @param proof The merkle proof supplied by the user to prove ownership of the claim
* @param recipient The address that will receive the claimed points
* @param amount The amount of points claimed
*/
function claimB(bytes32[] calldata proof, address recipient, uint256 amount, address[] calldata giftRecipients, uint256 giftAmount) external {
require(!claimedB[msg.sender], "Points: already claimed");
require(giftAmount <= amount, "Points: gift amount exceeds claim"); // Would underflow anyway but you can never be too safe
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender, amount))));
require(MerkleProofLib.verifyCalldata(proof, merkleRootB, leaf), "Points: invalid proof");
claimedB[msg.sender] = true;
if (giftAmount != 0) {
uint256 perUser = giftAmount / giftRecipients.length;
amount -= giftAmount;
for (uint256 i = 0; i < giftRecipients.length; ) {
balanceOf[giftRecipients[i]] += perUser;
unchecked {
++i;
}
}
}
totalSupply += amount + giftAmount;
// Mint the points to the recipient
unchecked {
balanceOf[recipient] += amount;
}
emit ClaimedB(msg.sender, recipient, amount);
}
/*
* @notice Unlike ERC20, Points do not return a boolean on transfer
* @param to The address that will receive the points
* @param amount The amount of points to transfer
*/
function transfer(address to, uint256 amount) external onlyWhitelisted {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
}
/*
* @notice Unlike ERC20, Points do not return a boolean on transfer
* @param from The address that will send the points
* @param to The address that will receive the points
* @param amount The amount of points to transfer
*/
function transferFrom(address from, address to, uint256 amount) external onlyWhitelisted {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
}
/*
* @param spender The address that will be allowed to spend the points
* @param amount The amount of points the spender will be allowed to spend
*/
function approve(address spender, uint256 amount) external onlyWhitelisted {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.23;
interface IBestFriend {
function addBonusPoints(uint256 _amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
library MerkleProofLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MERKLE PROOF VERIFICATION OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf)
internal
pure
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
if mload(proof) {
// Initialize `offset` to the offset of `proof` elements in memory.
let offset := add(proof, 0x20)
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(offset, shl(5, mload(proof)))
// Iterate over proof elements to compute root hash.
for {} 1 {} {
// Slot of `leaf` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(leaf, mload(offset)))
// Store elements to hash contiguously in scratch space.
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
mstore(scratch, leaf)
mstore(xor(scratch, 0x20), mload(offset))
// Reuse `leaf` to store the hash to reduce stack operations.
leaf := keccak256(0x00, 0x40)
offset := add(offset, 0x20)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf)
internal
pure
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
if proof.length {
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(proof.offset, shl(5, proof.length))
// Initialize `offset` to the offset of `proof` in the calldata.
let offset := proof.offset
// Iterate over proof elements to compute root hash.
for {} 1 {} {
// Slot of `leaf` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(leaf, calldataload(offset)))
// Store elements to hash contiguously in scratch space.
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
mstore(scratch, leaf)
mstore(xor(scratch, 0x20), calldataload(offset))
// Reuse `leaf` to store the hash to reduce stack operations.
leaf := keccak256(0x00, 0x40)
offset := add(offset, 0x20)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
/// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
/// given `proof` and `flags`.
///
/// Note:
/// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
/// will always return false.
/// - The sum of the lengths of `proof` and `leaves` must never overflow.
/// - Any non-zero word in the `flags` array is treated as true.
/// - The memory offset of `proof` must be non-zero
/// (i.e. `proof` is not pointing to the scratch space).
function verifyMultiProof(
bytes32[] memory proof,
bytes32 root,
bytes32[] memory leaves,
bool[] memory flags
) internal pure returns (bool isValid) {
// Rebuilds the root by consuming and producing values on a queue.
// The queue starts with the `leaves` array, and goes into a `hashes` array.
// After the process, the last element on the queue is verified
// to be equal to the `root`.
//
// The `flags` array denotes whether the sibling
// should be popped from the queue (`flag == true`), or
// should be popped from the `proof` (`flag == false`).
/// @solidity memory-safe-assembly
assembly {
// Cache the lengths of the arrays.
let leavesLength := mload(leaves)
let proofLength := mload(proof)
let flagsLength := mload(flags)
// Advance the pointers of the arrays to point to the data.
leaves := add(0x20, leaves)
proof := add(0x20, proof)
flags := add(0x20, flags)
// If the number of flags is correct.
for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} {
// For the case where `proof.length + leaves.length == 1`.
if iszero(flagsLength) {
// `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root)
break
}
// The required final proof offset if `flagsLength` is not zero, otherwise zero.
let proofEnd := add(proof, shl(5, proofLength))
// We can use the free memory space for the queue.
// We don't need to allocate, since the queue is temporary.
let hashesFront := mload(0x40)
// Copy the leaves into the hashes.
// Sometimes, a little memory expansion costs less than branching.
// Should cost less, even with a high free memory offset of 0x7d00.
leavesLength := shl(5, leavesLength)
for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } {
mstore(add(hashesFront, i), mload(add(leaves, i)))
}
// Compute the back of the hashes.
let hashesBack := add(hashesFront, leavesLength)
// This is the end of the memory for the queue.
// We recycle `flagsLength` to save on stack variables (sometimes save gas).
flagsLength := add(hashesBack, shl(5, flagsLength))
for {} 1 {} {
// Pop from `hashes`.
let a := mload(hashesFront)
// Pop from `hashes`.
let b := mload(add(hashesFront, 0x20))
hashesFront := add(hashesFront, 0x40)
// If the flag is false, load the next proof,
// else, pops from the queue.
if iszero(mload(flags)) {
// Loads the next proof.
b := mload(proof)
proof := add(proof, 0x20)
// Unpop from `hashes`.
hashesFront := sub(hashesFront, 0x20)
}
// Advance to the next flag.
flags := add(flags, 0x20)
// Slot of `a` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(a, b))
// Hash the scratch space and push the result onto the queue.
mstore(scratch, a)
mstore(xor(scratch, 0x20), b)
mstore(hashesBack, keccak256(0x00, 0x40))
hashesBack := add(hashesBack, 0x20)
if iszero(lt(hashesBack, flagsLength)) { break }
}
isValid :=
and(
// Checks if the last value in the queue is same as the root.
eq(mload(sub(hashesBack, 0x20)), root),
// And whether all the proofs are used, if required.
eq(proofEnd, proof)
)
break
}
}
}
/// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
/// given `proof` and `flags`.
///
/// Note:
/// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
/// will always return false.
/// - Any non-zero word in the `flags` array is treated as true.
/// - The calldata offset of `proof` must be non-zero
/// (i.e. `proof` is from a regular Solidity function with a 4-byte selector).
function verifyMultiProofCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32[] calldata leaves,
bool[] calldata flags
) internal pure returns (bool isValid) {
// Rebuilds the root by consuming and producing values on a queue.
// The queue starts with the `leaves` array, and goes into a `hashes` array.
// After the process, the last element on the queue is verified
// to be equal to the `root`.
//
// The `flags` array denotes whether the sibling
// should be popped from the queue (`flag == true`), or
// should be popped from the `proof` (`flag == false`).
/// @solidity memory-safe-assembly
assembly {
// If the number of flags is correct.
for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} {
// For the case where `proof.length + leaves.length == 1`.
if iszero(flags.length) {
// `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
// forgefmt: disable-next-item
isValid := eq(
calldataload(
xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length))
),
root
)
break
}
// The required final proof offset if `flagsLength` is not zero, otherwise zero.
let proofEnd := add(proof.offset, shl(5, proof.length))
// We can use the free memory space for the queue.
// We don't need to allocate, since the queue is temporary.
let hashesFront := mload(0x40)
// Copy the leaves into the hashes.
// Sometimes, a little memory expansion costs less than branching.
// Should cost less, even with a high free memory offset of 0x7d00.
calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length))
// Compute the back of the hashes.
let hashesBack := add(hashesFront, shl(5, leaves.length))
// This is the end of the memory for the queue.
// We recycle `flagsLength` to save on stack variables (sometimes save gas).
flags.length := add(hashesBack, shl(5, flags.length))
// We don't need to make a copy of `proof.offset` or `flags.offset`,
// as they are pass-by-value (this trick may not always save gas).
for {} 1 {} {
// Pop from `hashes`.
let a := mload(hashesFront)
// Pop from `hashes`.
let b := mload(add(hashesFront, 0x20))
hashesFront := add(hashesFront, 0x40)
// If the flag is false, load the next proof,
// else, pops from the queue.
if iszero(calldataload(flags.offset)) {
// Loads the next proof.
b := calldataload(proof.offset)
proof.offset := add(proof.offset, 0x20)
// Unpop from `hashes`.
hashesFront := sub(hashesFront, 0x20)
}
// Advance to the next flag offset.
flags.offset := add(flags.offset, 0x20)
// Slot of `a` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(a, b))
// Hash the scratch space and push the result onto the queue.
mstore(scratch, a)
mstore(xor(scratch, 0x20), b)
mstore(hashesBack, keccak256(0x00, 0x40))
hashesBack := add(hashesBack, 0x20)
if iszero(lt(hashesBack, flags.length)) { break }
}
isValid :=
and(
// Checks if the last value in the queue is same as the root.
eq(mload(sub(hashesBack, 0x20)), root),
// And whether all the proofs are used, if required.
eq(proofEnd, proof.offset)
)
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes32 array.
function emptyProof() internal pure returns (bytes32[] calldata proof) {
/// @solidity memory-safe-assembly
assembly {
proof.length := 0
}
}
/// @dev Returns an empty calldata bytes32 array.
function emptyLeaves() internal pure returns (bytes32[] calldata leaves) {
/// @solidity memory-safe-assembly
assembly {
leaves.length := 0
}
}
/// @dev Returns an empty calldata bool array.
function emptyFlags() internal pure returns (bool[] calldata flags) {
/// @solidity memory-safe-assembly
assembly {
flags.length := 0
}
}
}/// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
interface IPoints {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/// @notice By maintaining ERC20 compatibility, transfers and approvals are easier to index
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/// @notice Keep track of whether or not a user has claimed their points
event ClaimedA(address indexed _owner, address indexed recipient, uint256 indexed amount);
event ClaimedB(address indexed _owner, address indexed recipient, uint256 indexed amount);
/*//////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////*/
/*
* @param proof The merkle proof supplied by the user to prove ownership of the claim
* @param recipient The address that will receive the claimed points
* @param amount The amount of points claimed
*/
function claimA(bytes32[] calldata proof, address recipient, uint256 amount, address[] calldata giftRecipients, uint256 giftAmount) external;
function claimB(bytes32[] calldata proof, address recipient, uint256 amount, address[] calldata giftRecipients, uint256 giftAmount) external;
/*
* @notice Unlike ERC20, Points do not return a boolean on transfer
* @param to The address that will receive the points
* @param value The amount of points to transfer
*/
function transfer(address to, uint256 value) external;
/*
* @notice Unlike ERC20, Points do not return a boolean on transfer
* @param from The address that will send the points
* @param to The address that will receive the points
* @param value The amount of points to transfer
*/
function transferFrom(address from, address to, uint256 value) external;
/*
* @param spender The address that will be allowed to spend the points
* @param amount The amount of points the spender will be allowed to spend
*/
function approve(address spender, uint256 amount) external;
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/*
* @param _owner The address that will be allowed to spend the points
* @param _spender The address that will be allowed to spend the points
*
* @return The amount of points the spender is allowed to spend
*/
function allowance(address _owner, address _spender) external view returns (uint256);
/*
* @param _owner The address that will be checked for points
*
* @return The amount of points the owner has
*/
function balanceOf(address _owner) external view returns (uint256);
/*
* @return The root of the Merkle Tree which stores claims
*/
function merkleRootA() external view returns (bytes32);
/*//////////////////////////////////////////////////////////////
ACCESS CONTROL
//////////////////////////////////////////////////////////////*/
/*
* @param _address The address in question
*
* @return Whether the contract is allowed to interact with points
*/
function isAllowed(address _address) external view returns (bool);
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"murky/=lib/murky/",
"openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",
"solady/=lib/solady/src/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract Points","name":"_points","type":"address"},{"components":[{"internalType":"contract IERC20","name":"lpToken","type":"address"},{"internalType":"uint256","name":"lastRewardBlock","type":"uint256"},{"internalType":"uint256","name":"bonusPointsAccrued","type":"uint256"},{"internalType":"uint256","name":"bonusPointsDistributed","type":"uint256"},{"internalType":"uint256","name":"accpointsPerShare","type":"uint256"}],"internalType":"struct BestFriend.PoolInfo","name":"_pool","type":"tuple"},{"internalType":"uint256","name":"_pointsPerBlock","type":"uint256"},{"internalType":"uint256","name":"_endBlock","type":"uint256"},{"internalType":"address","name":"_router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addBonusPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"onBehalfOf","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newEndBlock","type":"uint256"}],"name":"extendEndBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"pendingpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"points","outputs":[{"internalType":"contract Points","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pointsPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"contract IERC20","name":"lpToken","type":"address"},{"internalType":"uint256","name":"lastRewardBlock","type":"uint256"},{"internalType":"uint256","name":"bonusPointsAccrued","type":"uint256"},{"internalType":"uint256","name":"bonusPointsDistributed","type":"uint256"},{"internalType":"uint256","name":"accpointsPerShare","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wag","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"onBehalfOf","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
0x60e06040523480156200001157600080fd5b5060405162001410380380620014108339810160408190526200003491620000fd565b600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b03948516608090815260a0939093526001919091558251600280546001600160a01b0319169186169190911790556020830151600355604083015160045560608301516005559101516006551660c052620001d4565b6001600160a01b0381168114620000e857600080fd5b50565b8051620000f881620000d2565b919050565b60008060008060008587036101208112156200011857600080fd5b86516200012581620000d2565b955060a0601f19820112156200013a57600080fd5b5060405160a081016001600160401b03811182821017156200016c57634e487b7160e01b600052604160045260246000fd5b6040526200017d60208801620000eb565b815260408701516020820152606087015160408201526080870151606082015260a087015160808201528094505060c0860151925060e08601519150620001c86101008701620000eb565b90509295509295909350565b60805160a05160c0516111db620002356000396000818161030101528181610342015261086f01526000818161023f01528181610c650152610efd0152600081816101f30152818161057a0152818161075601526109c801526111db6000f3fe608060405234801561001057600080fd5b50600436106100ff5760003560e01c80636e553f6511610097578063e3161ddd11610066578063e3161ddd146102d5578063f2fde38b146102dd578063f5dbced2146102f0578063f887ea40146102fc57600080fd5b80636e553f65146102875780638da5cb5b1461029a578063afa0120b146102ba578063db2e21bc146102cd57600080fd5b80631be6dd64116100d35780631be6dd64146101ee5780633fdb1e8f1461023a57806353e82334146102615780636dcec4b81461027457600080fd5b8062f714ce14610104578063083c63231461011957806316f0115b146101355780631959a002146101a4575b600080fd5b61011761011236600461108c565b610323565b005b61012260015481565b6040519081526020015b60405180910390f35b6002546003546004546005546006546101659473ffffffffffffffffffffffffffffffffffffffff169392919085565b6040805173ffffffffffffffffffffffffffffffffffffffff90961686526020860194909452928401919091526060830152608082015260a00161012c565b6101d36101b23660046110b8565b60076020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161012c565b6102157f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161012c565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b61011761026f3660046110da565b610706565b6101176102823660046110da565b6107ca565b61011761029536600461108c565b610850565b6000546102159073ffffffffffffffffffffffffffffffffffffffff1681565b6101226102c83660046110b8565b610b57565b610117610d02565b610117610e02565b6101176102eb3660046110b8565b610f72565b61012264e8d4a5100081565b6102157f000000000000000000000000000000000000000000000000000000000000000081565b73ffffffffffffffffffffffffffffffffffffffff811633146103e4577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1633146103e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f77697468647261773a206e6f7420617574686f72697a6564000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090206001810154831115610477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f77697468647261773a206e6f7420676f6f64000000000000000000000000000060448201526064016103db565b80544390610486906005611122565b106104ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f77697468647261773a207761697400000000000000000000000000000000000060448201526064016103db565b6104f5610e02565b6000816002015464e8d4a510006002600401548460010154610517919061113b565b6105219190611152565b61052b919061118d565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401600060405180830381600087803b1580156105c057600080fd5b505af11580156105d4573d6000803e3d6000fd5b505050508382600101546105e8919061118d565b6001830181905560065464e8d4a5100091610603919061113b565b61060d9190611152565b600283810191909155546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810186905273ffffffffffffffffffffffffffffffffffffffff9091169063a9059cbb906044016020604051808303816000875af115801561068b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106af91906111a0565b508273ffffffffffffffffffffffffffffffffffffffff167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364856040516106f891815260200190565b60405180910390a250505050565b600454610714908290611122565b60049081556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523391810191909152306024820152604481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401600060405180830381600087803b1580156107af57600080fd5b505af11580156107c3573d6000803e3d6000fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103db565b600155565b73ffffffffffffffffffffffffffffffffffffffff8116331461090c577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16331461090c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6465706f7369743a206e6f7420617574686f72697a656400000000000000000060448201526064016103db565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600760205260409020610939610e02565b600181015415610a28576000816002015464e8d4a510006002600401548460010154610965919061113b565b61096f9190611152565b610979919061118d565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401600060405180830381600087803b158015610a0e57600080fd5b505af1158015610a22573d6000803e3d6000fd5b50505050505b6002546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af1158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac991906111a0565b50828160010154610ada9190611122565b6001820181905560065464e8d4a5100091610af5919061113b565b610aff9190611152565b600282015543815560405183815273ffffffffffffffffffffffffffffffffffffffff8316907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2505050565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526007602052604080822060065460025492517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152939491939092859216906370a0823190602401602060405180830381865afa158015610bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0391906111c2565b905060006001544310610c1857600154610c1a565b435b60035490915043118015610c2d57508115155b15610cc9576003546000908211610c4657506000610c56565b600354610c53908361118d565b90505b60055460045460009190610c8a7f00000000000000000000000000000000000000000000000000000000000000008561113b565b610c949190611122565b610c9e919061118d565b905083610cb064e8d4a510008361113b565b610cba9190611152565b610cc49086611122565b945050505b836002015464e8d4a51000848660010154610ce4919061113b565b610cee9190611152565b610cf8919061118d565b9695505050505050565b3360008181526007602052604090819020600254600182015492517fa9059cbb000000000000000000000000000000000000000000000000000000008152600481019490945260248401929092529173ffffffffffffffffffffffffffffffffffffffff9091169063a9059cbb906044016020604051808303816000875af1158015610d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db691906111a0565b50600181015460405190815233907f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd96959060200160405180910390a2600060018201819055600290910155565b6003544311610e0d57565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea091906111c2565b905080600003610eb1575043600355565b60006001544310610ec457600154610ec6565b435b905060006002600101548211610ede57506000610eee565b600354610eeb908361118d565b90505b60055460045460009190610f227f00000000000000000000000000000000000000000000000000000000000000008561113b565b610f2c9190611122565b610f36919061118d565b905083610f4864e8d4a510008361113b565b610f529190611152565b600654610f5f9190611122565b6006555050436003555050600454600555565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ff3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103db565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b803573ffffffffffffffffffffffffffffffffffffffff8116811461108757600080fd5b919050565b6000806040838503121561109f57600080fd5b823591506110af60208401611063565b90509250929050565b6000602082840312156110ca57600080fd5b6110d382611063565b9392505050565b6000602082840312156110ec57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115611135576111356110f3565b92915050565b8082028115828204841417611135576111356110f3565b600082611188577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115611135576111356110f3565b6000602082840312156111b257600080fd5b815180151581146110d357600080fd5b6000602082840312156111d457600080fd5b5051919050560000000000000000000000000bd4887f7d41b35cd75dff9ffee2856106f866700000000000000000000000007cfc830448484cdf830625373820241e61ef4acf0000000000000000000000000000000000000000000000000000000000d4b3c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8fb8c0bd6a60000000000000000000000000000000000000000000000000000000000001c54d87000000000000000000000000bf250ae227de43dedaf01ccbfd8cc83027efc1e2
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100ff5760003560e01c80636e553f6511610097578063e3161ddd11610066578063e3161ddd146102d5578063f2fde38b146102dd578063f5dbced2146102f0578063f887ea40146102fc57600080fd5b80636e553f65146102875780638da5cb5b1461029a578063afa0120b146102ba578063db2e21bc146102cd57600080fd5b80631be6dd64116100d35780631be6dd64146101ee5780633fdb1e8f1461023a57806353e82334146102615780636dcec4b81461027457600080fd5b8062f714ce14610104578063083c63231461011957806316f0115b146101355780631959a002146101a4575b600080fd5b61011761011236600461108c565b610323565b005b61012260015481565b6040519081526020015b60405180910390f35b6002546003546004546005546006546101659473ffffffffffffffffffffffffffffffffffffffff169392919085565b6040805173ffffffffffffffffffffffffffffffffffffffff90961686526020860194909452928401919091526060830152608082015260a00161012c565b6101d36101b23660046110b8565b60076020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161012c565b6102157f0000000000000000000000000bd4887f7d41b35cd75dff9ffee2856106f8667081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161012c565b6101227f0000000000000000000000000000000000000000000000000a8fb8c0bd6a600081565b61011761026f3660046110da565b610706565b6101176102823660046110da565b6107ca565b61011761029536600461108c565b610850565b6000546102159073ffffffffffffffffffffffffffffffffffffffff1681565b6101226102c83660046110b8565b610b57565b610117610d02565b610117610e02565b6101176102eb3660046110b8565b610f72565b61012264e8d4a5100081565b6102157f000000000000000000000000bf250ae227de43dedaf01ccbfd8cc83027efc1e281565b73ffffffffffffffffffffffffffffffffffffffff811633146103e4577f000000000000000000000000bf250ae227de43dedaf01ccbfd8cc83027efc1e273ffffffffffffffffffffffffffffffffffffffff1633146103e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f77697468647261773a206e6f7420617574686f72697a6564000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090206001810154831115610477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f77697468647261773a206e6f7420676f6f64000000000000000000000000000060448201526064016103db565b80544390610486906005611122565b106104ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f77697468647261773a207761697400000000000000000000000000000000000060448201526064016103db565b6104f5610e02565b6000816002015464e8d4a510006002600401548460010154610517919061113b565b6105219190611152565b61052b919061118d565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390529192507f0000000000000000000000000bd4887f7d41b35cd75dff9ffee2856106f866709091169063a9059cbb90604401600060405180830381600087803b1580156105c057600080fd5b505af11580156105d4573d6000803e3d6000fd5b505050508382600101546105e8919061118d565b6001830181905560065464e8d4a5100091610603919061113b565b61060d9190611152565b600283810191909155546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810186905273ffffffffffffffffffffffffffffffffffffffff9091169063a9059cbb906044016020604051808303816000875af115801561068b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106af91906111a0565b508273ffffffffffffffffffffffffffffffffffffffff167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364856040516106f891815260200190565b60405180910390a250505050565b600454610714908290611122565b60049081556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523391810191909152306024820152604481018290527f0000000000000000000000000bd4887f7d41b35cd75dff9ffee2856106f8667073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401600060405180830381600087803b1580156107af57600080fd5b505af11580156107c3573d6000803e3d6000fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103db565b600155565b73ffffffffffffffffffffffffffffffffffffffff8116331461090c577f000000000000000000000000bf250ae227de43dedaf01ccbfd8cc83027efc1e273ffffffffffffffffffffffffffffffffffffffff16331461090c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6465706f7369743a206e6f7420617574686f72697a656400000000000000000060448201526064016103db565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600760205260409020610939610e02565b600181015415610a28576000816002015464e8d4a510006002600401548460010154610965919061113b565b61096f9190611152565b610979919061118d565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390529192507f0000000000000000000000000bd4887f7d41b35cd75dff9ffee2856106f866709091169063a9059cbb90604401600060405180830381600087803b158015610a0e57600080fd5b505af1158015610a22573d6000803e3d6000fd5b50505050505b6002546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af1158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac991906111a0565b50828160010154610ada9190611122565b6001820181905560065464e8d4a5100091610af5919061113b565b610aff9190611152565b600282015543815560405183815273ffffffffffffffffffffffffffffffffffffffff8316907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2505050565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526007602052604080822060065460025492517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152939491939092859216906370a0823190602401602060405180830381865afa158015610bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0391906111c2565b905060006001544310610c1857600154610c1a565b435b60035490915043118015610c2d57508115155b15610cc9576003546000908211610c4657506000610c56565b600354610c53908361118d565b90505b60055460045460009190610c8a7f0000000000000000000000000000000000000000000000000a8fb8c0bd6a60008561113b565b610c949190611122565b610c9e919061118d565b905083610cb064e8d4a510008361113b565b610cba9190611152565b610cc49086611122565b945050505b836002015464e8d4a51000848660010154610ce4919061113b565b610cee9190611152565b610cf8919061118d565b9695505050505050565b3360008181526007602052604090819020600254600182015492517fa9059cbb000000000000000000000000000000000000000000000000000000008152600481019490945260248401929092529173ffffffffffffffffffffffffffffffffffffffff9091169063a9059cbb906044016020604051808303816000875af1158015610d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db691906111a0565b50600181015460405190815233907f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd96959060200160405180910390a2600060018201819055600290910155565b6003544311610e0d57565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea091906111c2565b905080600003610eb1575043600355565b60006001544310610ec457600154610ec6565b435b905060006002600101548211610ede57506000610eee565b600354610eeb908361118d565b90505b60055460045460009190610f227f0000000000000000000000000000000000000000000000000a8fb8c0bd6a60008561113b565b610f2c9190611122565b610f36919061118d565b905083610f4864e8d4a510008361113b565b610f529190611152565b600654610f5f9190611122565b6006555050436003555050600454600555565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ff3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103db565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b803573ffffffffffffffffffffffffffffffffffffffff8116811461108757600080fd5b919050565b6000806040838503121561109f57600080fd5b823591506110af60208401611063565b90509250929050565b6000602082840312156110ca57600080fd5b6110d382611063565b9392505050565b6000602082840312156110ec57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115611135576111356110f3565b92915050565b8082028115828204841417611135576111356110f3565b600082611188577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115611135576111356110f3565b6000602082840312156111b257600080fd5b815180151581146110d357600080fd5b6000602082840312156111d457600080fd5b505191905056
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.