Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"rainlink-contract-main/core/Messager.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import {ECDSA} from "@openzeppelin/contracts@5.0.0/utils/cryptography/ECDSA.sol";
import {Address} from "@openzeppelin/contracts@5.0.0/utils/Address.sol";
import {Types} from "../comn/Types.sol";
import {IMessager} from "../comn/IMessager.sol";
import {IValidator} from "../comn/IValidator.sol";
import {ComFunUtil} from "../comn/ComFunUtil.sol";
import {Comn} from "./Comn.sol";
/**
* @title Messager
* @dev This contract inherits from both Comn and IMessager. It is designed to handle messaging - related operations in the context of a cross - chain or decentralized system.
* It may be responsible for emitting, consuming, and decoding messages, which are crucial for coordinating actions between different components, chains, or contracts.
* The contract serves as a communication hub to ensure the proper flow of information and execution of associated tasks within the overall system.
*/
contract Messager is Comn, IMessager {
uint public bridge_fee;
// The fee for cross - chain bridging operations.
// Mapping from target chain ID to a nonce value. Nonce starts from 1 for each chain ID.
// to chain_id => id start from 1
mapping(uint => uint) public nonceMap;
// Mapping from source chain ID to another mapping of nonce to a boolean indicating if the nonce has been used.
// from chain_id => (nonce => bool)
mapping(uint => mapping(uint => bool)) public nonceStateMap;
/**
* @dev Sets the bridge fee. Only the administrator can call this function.
* @param _bridge_fee The new bridge fee to be set.
*/
function set_bridge_fee(uint _bridge_fee) public onlyAdmin {
bridge_fee = _bridge_fee;
}
/**
* @dev Decodes a bytes - encoded message into a Types.Message struct.
* @param message The bytes array representing the encoded message.
* @return A Types.Message struct decoded from the input bytes.
*/
function decode_msg(
bytes memory message
) public pure returns (Types.Message memory) {
return abi.decode(message, (Types.Message));
}
/**
* @dev Decodes the body of a bridge message from a calldata bytes.
* @param msg_body The calldata bytes representing the ABI - packed bridge message body.
* @return A Types.BridgeMessageBody struct decoded from the input bytes.
*/
function decode_bridge_msg_body(
bytes calldata msg_body // this is a abi packed type
) public pure returns (Types.BridgeMessageBody memory) {
bytes32 source_token = bytes32(msg_body[0:32]);
uint128 all_amount = uint128(bytes16(msg_body[32:48]));
// uint upload_gas_fee = uint(bytes32(msg_body[64:96]));
bytes32 from_who = bytes32(msg_body[48:80]);
bytes32 to_who = bytes32(msg_body[80:112]);
bytes calldata biz_data = msg_body[112:];
return
Types.BridgeMessageBody({
source_token: source_token,
all_amount: all_amount,
// upload_gas_fee: upload_gas_fee,
from_who: from_who,
to_who: to_who,
biz_data: biz_data
});
}
/**
* @dev Converts a Types.MessageHeader struct to a bytes array.
* @param header The Types.MessageHeader struct to be converted.
* @return A bytes array representing the encoded message header.
*/
function _convert_header_to_bytes(
Types.MessageHeader memory header
) private pure returns (bytes memory) {
return
abi.encodePacked(
header.msg_type,
header.nonce,
ComFunUtil.combainChain(header.from_chain),
header.sender,
ComFunUtil.combainChain(header.to_chain),
header.receiver,
header.upload_gas_fee
);
}
/**
* @dev Verifies the signature of a message and checks if it meets the minimum validator requirements.
* @param messageDec The decoded Types.Message struct.
* @param signature An array of bytes representing the signatures of the message.
* @return A boolean indicating if the message is valid and the original decoded message.
*/
function _verify_msg(
Types.Message memory messageDec,
bytes[] memory signature
) private returns (bool, Types.Message memory) {
bytes32 msgHash = keccak256(
bytes.concat(
_convert_header_to_bytes(messageDec.msg_header),
messageDec.msg_body
)
);
emit Types.Log("msgHash in verify_msg: ", msgHash);
Types.Message memory msgDec = messageDec;
(address[] memory validators, uint min_verify_threshold) = IValidator(
ValidatorAddr
).fetch_all_validators();
if (signature.length < min_verify_threshold) {
emit Types.Log("require min verify node", min_verify_threshold);
return (false, msgDec);
}
uint256 validSignerCount = 0;
bool[] memory uniqueSigners = new bool[](validators.length);
for (uint i = 0; i < signature.length; i++) {
address msg_signer = ECDSA.recover(msgHash, signature[i]);
if (!isValidator(msg_signer, validators)) {
revert("Not a valid signer node");
}
uint256 signerIndex = getValidatorIndex(msg_signer, validators);
if (!uniqueSigners[signerIndex]) {
uniqueSigners[signerIndex] = true;
validSignerCount++;
}
}
require(
validSignerCount >= min_verify_threshold,
"not meet minimum signer requirement"
);
return (true, msgDec);
}
/**
* @dev Checks if an address is a validator.
* @param signer The address to be checked.
* @param validators An array of validator addresses.
* @return A boolean indicating if the address is a validator.
*/
function isValidator(
address signer,
address[] memory validators
) private pure returns (bool) {
for (uint256 i = 0; i < validators.length; i++) {
if (validators[i] == signer) {
return true;
}
}
return false;
}
/**
* @dev Gets the index of a validator address in the validators array.
* @param signer The address of the validator.
* @param validators An array of validator addresses.
* @return The index of the validator address in the array.
*/
function getValidatorIndex(
address signer,
address[] memory validators
) private pure returns (uint256) {
for (uint256 i = 0; i < validators.length; i++) {
if (validators[i] == signer) {
return i;
}
}
revert("Signer not found in validators");
}
/**
* @dev Verifies the signature of a message and returns a boolean indicating its validity.
* @param messageDec The decoded Types.Message struct.
* @param signature An array of bytes representing the signatures of the message.
* @return A boolean indicating if the message is valid.
*/
function verify_msg(
Types.Message memory messageDec,
bytes[] memory signature
) public returns (bool) {
(bool rs, ) = _verify_msg(messageDec, signature);
return rs;
}
/**
* @dev Verifies the signature of a bridge message and consumes it by marking the nonce as used.
* @param messageDec The decoded Types.Message struct.
* @param signature An array of bytes representing the signatures of the message.
* @return A boolean indicating if the message is valid and can be consumed.
*/
function consume_bridge_msg(
Types.Message memory messageDec,
bytes[] memory signature
) public returns (bool) {
address receiver = ComFunUtil.bytes32ToAddress(
messageDec.msg_header.receiver
);
require(msg.sender == receiver, "not match receiver");
(bool rs, ) = _verify_msg(messageDec, signature);
uint from_chain_id = ComFunUtil.combainChain(
messageDec.msg_header.from_chain
);
uint nonce = messageDec.msg_header.nonce;
// not empty key
if (nonceStateMap[from_chain_id][nonce]) {
emit Types.Log("nonce has been used");
return false;
} else {
nonceStateMap[from_chain_id][nonce] = true;
}
return rs;
}
/**
* @dev Emits a message for cross - chain communication.
* @param msg_type The type of the message.
* @param to_chain The target chain information.
* @param receiver The receiver's identifier in bytes32 format.
* @param body_message The body of the message in bytes.
* @param upload_gas_fee The gas fee for uploading the message.
*/
function emit_msg(
uint8 msg_type,
Types.Chain memory to_chain,
bytes32 receiver,
bytes memory body_message,
uint128 upload_gas_fee
) public payable {
require(bridge_fee <= msg.value, "not enough gas");
require(upload_gas_fee > 0, "upload_gas_fee must greater than 0");
uint to_chain_uint = ComFunUtil.combainChain(to_chain);
nonceMap[to_chain_uint] += 1;
uint nonce = nonceMap[to_chain_uint];
require(
block.chainid <= type(uint64).max,
"chainid exceed the maximum"
);
require(nonce <= type(uint64).max, "nonce exceed the maximum");
Types.Message memory rs = Types.Message(
Types.MessageHeader({
msg_type: msg_type,
nonce: uint64(nonce),
from_chain: Types.Chain(
uint8(ChainType),
uint64(block.chainid)
),
sender: ComFunUtil.addressToBytes32(address(msg.sender)),
to_chain: to_chain,
receiver: receiver,
upload_gas_fee: upload_gas_fee
}),
body_message
);
emit Msg(rs);
emit UploadFee(upload_gas_fee);
}
/**
* @dev Allows a admin to withdraw the bridge fee.
* @param amount The amount to be withdrawn.
*/
function withdrawFee(uint amount) public onlyAdmin {
require(amount <= address(this).balance, "not enough balance");
Address.sendValue(payable(msg.sender), amount);
}
}
"
},
"rainlink-contract-main/core/Comn.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import "../BaseComn.sol";
import {Types} from "../comn/Types.sol";
/**
* @title all sol extends from this
* @dev Extends BaseComn with additional address constants
*/
abstract contract Comn is BaseComn {
// xone
address constant ValidatorAddr = address(0xfeBc13df64252cb83FbDAFa8d916867dAa30501a);
// tbsc
// address constant ValidatorAddr = address(0x237aeC76ED2bECC3e5df4f007F6E67CC2EAe68e9);
// sepolia
// address constant ValidatorAddr = address(0x1F1C9CFF1c78cE6d530b218dF61f25D7849A1791);
// nile
// address constant ValidatorAddr = address(0xa85E0F60586EbB70d05cE01D09B5750C04f8e046); //TRKTChDwwjFTi9mmL6iePHV6X2C42YN3TN
// ETH chain
Types.ChainType constant ChainType = Types.ChainType.ETH;
// TRX chain
// Types.ChainType constant ChainType = Types.ChainType.TRX;
}"
},
"rainlink-contract-main/comn/ComFunUtil.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import {Types} from "./Types.sol";
library ComFunUtil {
function isNotEmpty(address ad, string memory msgs) private pure {
require(ad != address(0), msgs);
}
function isNotEmpty(uint ad, string memory msgs) private pure {
require(ad != 0, msgs);
}
function combainChain(
Types.Chain memory chain_
) internal pure returns (uint72) {
uint72 c = chain_.chain_id;
// must use uint72 to avoid u8 overflow
uint72 chain_type = chain_.chain_type;
c += chain_type << 64;
return c;
}
function splitChain(uint a1) internal pure returns (Types.Chain memory c) {
c.chain_id = uint64(a1);
c.chain_type = uint8(a1 >> 64);
}
function addressToBytes32(address a) internal pure returns (bytes32 b) {
return bytes32(uint(uint160(a)));
}
function bytes32ToAddress(bytes32 a) internal pure returns (address b) {
return address(uint160(uint(a)));
}
function hexStr2bytes32(string memory data) internal pure returns (bytes32) {
return bytes2bytes32(hexStr2bytes(data));
}
function bytes2bytes32(bytes memory data) internal pure returns (bytes32) {
uint len = data.length;
if (len > 32) {
revert("data len is overflow 32");
}
uint rs = 0;
for (uint i = 0; i < len; i++) {
rs = rs << 8;
rs += uint8(data[i]);
}
return bytes32(rs);
}
// convert hex string to bytes
function hexStr2bytes(
string memory data
) internal pure returns (bytes memory) {
bytes memory a = bytes(data);
if (a.length % 2 != 0) {
revert("hex string len is invalid");
}
uint8[] memory b = new uint8[](a.length);
for (uint i = 0; i < a.length; i++) {
uint8 _a = uint8(a[i]);
if (_a > 96) {
b[i] = _a - 97 + 10;
} else if (_a > 66) {
b[i] = _a - 65 + 10;
} else {
b[i] = _a - 48;
}
}
bytes memory c = new bytes(b.length / 2);
for (uint _i = 0; _i < b.length; _i += 2) {
c[_i / 2] = bytes1(b[_i] * 16 + b[_i + 1]);
}
return c;
}
function stringConcat(
string memory a,
string memory b,
bytes memory d
) internal pure returns (string memory) {
bytes memory a1 = bytes(a);
bytes memory a2 = bytes(b);
bytes memory a3;
a3 = new bytes(a1.length + a2.length + d.length);
uint k = 0;
for (uint i = 0; i < a1.length; i++) {
a3[k++] = a1[i];
}
for (uint i = 0; i < d.length; i++) {
a3[k++] = d[i];
}
for (uint i = 0; i < a2.length; i++) {
a3[k++] = a2[i];
}
return string(a3);
}
function currentTimestamp() internal view returns (uint256) {
return block.timestamp;
}
}
"
},
"rainlink-contract-main/comn/IValidator.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
interface IValidator {
function batch_add_validators(
bytes32[] memory signer_pk,
uint threshold
) external;
function batch_delete_validators(bytes32[] memory signer_pk) external returns (uint);
function set_min_verify_threshold(uint v) external;
function get_min_verify_threshold() external view returns (uint);
function fetch_all_validators()
external
view
returns (address[] memory, uint);
}
"
},
"rainlink-contract-main/comn/IMessager.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import "./Types.sol";
interface IMessager {
event Msg(Types.Message);
event UploadFee(uint);
function set_bridge_fee(uint v) external;
function verify_msg(
Types.Message memory messageDec,
// uint16[] memory signer_index,
bytes[] memory signature
) external returns (bool);
function decode_msg(
bytes memory message
) external pure returns (Types.Message memory);
function decode_bridge_msg_body(
bytes memory msg_body
) external pure returns (Types.BridgeMessageBody memory);
// verify and consume it.
function consume_bridge_msg(
Types.Message memory messageDec,
bytes[] memory signature
) external returns (bool);
function emit_msg(
uint8 msg_type,
Types.Chain memory to_chain,
bytes32 receiver,
bytes memory message,
uint128 upload_gas_fee // source p token.
) external payable;
function withdrawFee(uint amount) external;
}
"
},
"rainlink-contract-main/comn/Types.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
// all data in this file we should remain static.
// as this file may be used when create empty StoreHouse. to avoid any data not being initialized. we should keet it static.
library Types {
event Log(string);
event Log(string, bytes);
event Log(uint);
event Log(string, uint);
event Log(string, bytes32);
event Log(string, bytes32, uint);
event Log(string, address);
struct PoolInfo {
address token;
uint amount; // actual remain amount.
uint inAmount; // all in token = all in lock amount + all in stake amount.
uint lockAmount; // actual locked by contract
uint stakeAmount; // actual user stake into contract.
uint rewardAmount; // reward for staker, will used in future. now all reward will added to stake amount.
uint acc; // Q64.64
uint last_apy; // Q64.64
uint last_receive_rewards_time;
}
enum AmountType {
locked,
staked
}
enum TokenType {
pool,
mint
}
struct UserAmountInfo {
address token;
uint8 amountType; // 0 locked value. 1 staked value.
uint amount;
uint debt;
uint remainReward;
// for locked user. all amount = amount
// for stake user all amount = amount*acc - debt + amount + remainReward
}
// for front end.
struct UserAmountInfoForView {
address token;
uint8 amountType; // 0 locked value. 1 staked value.
uint amount;
uint debt;
uint remainReward;
uint acc;
uint bonus;
// for locked user. all amount = amount
// for stake user all amount = amount*acc - debt + amount + remainReward
}
// for front end.
struct UserAmountInfoForViewV2 {
address token;
uint8 amountType; // 0 locked value. 1 staked value.
uint amount;
uint debt;
uint remainReward;
uint acc;
uint bonus;
// for locked user. all amount = amount
// for stake user all amount = amount*acc - debt + amount + remainReward
uint earns;
}
struct FromSource {
uint source_chain_id;
bytes32 source_token;
}
struct RelationShipInfo {
address dest_token;
uint8 dest_token_type; // 0 for pool, 1 for new mint
}
struct SourceTokenInfo {
uint8 initialized;
uint8 decimals; // record the decimals for source token
}
struct CrossRelation {
uint source_chain_id;
bytes32 source_token;
uint8 source_token_decimals;
address dest_token;
uint8 dest_token_type;
}
struct MessageMeta {
// BridgeMessage bridgeMsg;
// // other fields
uint8 status; //
uint[4] reserves;
}
struct Chain {
uint8 chain_type;
uint64 chain_id;
}
enum ChainType {
ETH,
TRX,
SOL
}
struct Message {
MessageHeader msg_header;
bytes msg_body;
}
struct MessageHeader {
uint8 msg_type; // 0 means bridge message
uint64 nonce;
Chain from_chain; //
bytes32 sender;
// address messager;
Chain to_chain; //
bytes32 receiver;
uint128 upload_gas_fee;
}
struct BridgeMessageBody {
// body
bytes32 source_token;
uint128 all_amount;
// uint amount;
// uint platform_fee;
// uint upload_fee_price; // all amount = amount + platform_fee + upload_gas_fee * upload_fee_price
bytes32 from_who;
bytes32 to_who;
bytes biz_data;
// uint slipage;
}
struct ERC20Permit {
address owner;
address spender;
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
struct UserWithdrawData {
address token;
uint amount; // uni decimal.
// string symbol;
}
struct UserWithdrawDataDetail {
address token;
string symbol;
string name;
uint8 decimal;
uint amount;
}
struct ErrorObj {
uint key;
uint error_type;
string sMsg;
uint cMsg;
bytes bMsg;
string desc; // description
}
}
"
},
"@openzeppelin/contracts@5.0.0/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
"
},
"@openzeppelin/contracts@5.0.0/utils/cryptography/ECDSA.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}
"
},
"rainlink-contract-main/BaseComn.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import "./comn/IAdmin.sol";
import {StorageSlot} from "@openzeppelin/contracts@5.0.0/utils/StorageSlot.sol";
/**
* @title BaseComn
* @dev Contains the core constants and base functionality
*/
abstract contract BaseComn {
bytes32 constant _ADMIN_SLOT =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
modifier onlyMaster() {
IAdmin(getAdminAddr()).mustMaster(msg.sender);
_;
}
/**
* @dev Throws if called by any account other than the admin.
*/
modifier onlyAdmin() {
IAdmin(getAdminAddr()).mustAdmin(msg.sender);
_;
}
/**
* @dev Returns the admin address from storage slot
*/
function getAdminAddr() public view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
}
"
},
"@openzeppelin/contracts@5.0.0/utils/StorageSlot.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
"
},
"rainlink-contract-main/comn/IAdmin.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
/**
* @dev Interface for Admin
*/
interface IAdmin {
function mustMaster(address addr) external view;
function mustAdmin(address addr) external view;
function isMaster(address addr) external view returns (bool);
function isAdmin(address addr) external view returns (bool);
}
"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [],
"evmVersion": "london"
}
}}
Submitted on: 2025-09-20 14:31:49
Comments
Log in to comment.
No comments yet.