github.com/diadata-org/diadata@v1.4.593/pkg/dia/scraper/blockchain-scrapers/blockchains/ethereum/diaOracleV2Multiupdate/DIASignedOracleMultiple.sol (about) 1 // SPDX-License-Identifier: MIT 2 3 pragma solidity ^0.8.23; 4 5 import "@openzeppelin/contracts/access/Ownable.sol"; 6 7 contract DIASignedOracleMultiple is Ownable { 8 address public signer; 9 struct Message { 10 string Symbol; 11 address Address; 12 string Blockchain; 13 uint256 Price; 14 uint256 Time; 15 } 16 17 struct RawMessage { 18 string Symbol; 19 address Address; 20 string Blockchain; 21 uint256 Price; 22 uint256 Time; 23 bytes Signature; 24 } 25 26 mapping(string => Message) public values; 27 28 event OracleUpdate(string key, uint256 value, uint256 timestamp); 29 30 event RequestUpdate( 31 address assetAddress, 32 string blockchain, 33 uint256 timestamp 34 ); 35 36 constructor() Ownable(msg.sender) { 37 signer = msg.sender; 38 } 39 40 function setValues(RawMessage[] memory vs) public { 41 for (uint i = 0; i < vs.length; i++) { 42 this.setValue(vs[i]); 43 } 44 } 45 46 function setValue(RawMessage memory v) external { 47 require(getSigner(v) == signer, "SIGNER_DONT_MATCH"); 48 require(v.Time >= values[v.Symbol].Time, "NEWER_TIMESTAMP_REQUIRED"); 49 50 Message memory valueWithoutSignature = Message({ 51 Symbol: v.Symbol, 52 Address: v.Address, 53 Blockchain: v.Blockchain, 54 Price: v.Price, 55 Time: v.Time 56 }); 57 58 values[v.Symbol] = valueWithoutSignature; 59 emit OracleUpdate(v.Symbol, v.Price, v.Time); 60 } 61 62 function requestForUpdate( 63 address assetAddress, 64 string memory blockchain, 65 uint256 timestamp 66 ) external { 67 emit RequestUpdate(assetAddress, blockchain, timestamp); 68 } 69 70 function getValue( 71 string memory key 72 ) external view returns (Message memory) { 73 return values[key]; 74 } 75 76 function updateSigner(address _newSigner) external onlyOwner { 77 signer = _newSigner; 78 } 79 80 function changeOwner(address newOwner) external onlyOwner { 81 _transferOwnership(newOwner); 82 } 83 84 function getSigner(RawMessage memory message) public pure returns (address) { 85 bytes memory _signature; 86 _signature = message.Signature; 87 88 string 89 memory EIP712_DOMAIN_TYPE = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; 90 string 91 memory MESSAGE_TYPE = "Message(string Symbol,address Address,string Blockchain,uint256 Price,uint256 Time)"; 92 93 bytes32 DOMAIN_SEPARATOR = keccak256( 94 abi.encode( 95 keccak256(abi.encodePacked(EIP712_DOMAIN_TYPE)), 96 keccak256(abi.encodePacked("DiaData")), 97 keccak256(abi.encodePacked("1.0.0")), 98 1, 99 0x0000000000000000000000000000000000000000 100 ) 101 ); 102 103 bytes32 hash = keccak256( 104 abi.encodePacked( 105 "\x19\x01", // backslash is needed to escape the character 106 DOMAIN_SEPARATOR, 107 keccak256( 108 abi.encode( 109 keccak256(abi.encodePacked(MESSAGE_TYPE)), 110 keccak256(bytes(message.Symbol)), 111 message.Address, 112 keccak256(bytes(message.Blockchain)), 113 message.Price, 114 message.Time 115 ) 116 ) 117 ) 118 ); 119 120 // split signature 121 bytes32 r; 122 bytes32 s; 123 uint8 v; 124 if (_signature.length != 65) { 125 return address(0); 126 } 127 assembly { 128 r := mload(add(_signature, 32)) 129 s := mload(add(_signature, 64)) 130 v := byte(0, mload(add(_signature, 96))) 131 } 132 if (v < 27) { 133 v += 27; 134 } 135 if (v != 27 && v != 28) { 136 return address(0); 137 } else { 138 // verify 139 return ecrecover(hash, v, r, s); 140 } 141 } 142 }