Skip to content

Commit

Permalink
feat: contracts poc (#10)
Browse files Browse the repository at this point in the history
* feat: wip

* feat: wip

* fix: typos and storage vars

* fix: valid data sources in storage

* ci: solidity

* ci: typo

* fix: prettier

* ci: working dir
  • Loading branch information
EvolveArt authored Aug 27, 2024
1 parent e737996 commit 1ff5e3b
Show file tree
Hide file tree
Showing 10 changed files with 536 additions and 25 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ jobs:
name: Run Cargo linters
uses: ./.github/workflows/linters-cargo.yml
needs: rust_build

solidity_test:
name: Run Solidity tests
uses: ./.github/workflows/solidity-test.yml
10 changes: 8 additions & 2 deletions .github/workflows/solidity-test.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
name: solidity-test
name: Task - Test Solidity

on: workflow_dispatch
on:
workflow_dispatch:
workflow_call:

env:
FOUNDRY_PROFILE: ci

jobs:
check:
env:
working-directory: ./solidity
strategy:
fail-fast: true

Expand All @@ -23,12 +27,14 @@ jobs:
version: nightly

- name: Run Forge build
working-directory: ${{ env.working-directory }}
run: |
forge --version
forge build --sizes
id: build

- name: Run Forge tests
working-directory: ${{ env.working-directory }}
run: |
forge test -vvv
id: test
27 changes: 20 additions & 7 deletions solidity/src/Hyperlane.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,37 @@
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

import {HyMsg, Signature} from "./interfaces/IHyperlane.sol";
import {HyMsg, Signature, IHyperlane} from "./interfaces/IHyperlane.sol";
import "./libraries/BytesLib.sol";

contract Hyperlane {
contract Hyperlane is IHyperlane {
using BytesLib for bytes;

address[] public _validators;

function parseAndVerifyHyMsg(
bytes calldata encodedHyMsg
) public view returns (HyMsg memory hyMsg, bool valid, string memory reason) {
)
public
view
returns (HyMsg memory hyMsg, bool valid, string memory reason)
{
hyMsg = parseHyMsg(encodedHyMsg);
(valid, reason) = verifyHyMsg(hyMsg);
}

function verifyHyMsg(HyMsg memory hyMsg) public view returns (bool valid, string memory reason) {
function verifyHyMsg(
HyMsg memory hyMsg
) public view returns (bool valid, string memory reason) {
// TODO: fetch validators from calldata/storage
address[] memory validators = _validators;

if (validators.length == 0) {
return (false, "no validators announced");
}

// We're using a fixed point number transformation with 1 decimal to deal with rounding.
// we check that we have will be able to reach a quorum with the current signatures
if (
(((validators.length * 10) / 3) * 2) / 10 + 1 >
hyMsg.signatures.length
Expand All @@ -53,6 +60,7 @@ contract Hyperlane {
address[] memory validators
) public pure returns (bool valid, string memory reason) {
uint8 lastIndex = 0;
// TODO: break on quorum
for (uint i = 0; i < signatures.length; i++) {
Signature memory sig = signatures[i];

Expand All @@ -72,7 +80,9 @@ contract Hyperlane {
return (true, "");
}

function parseHyMsg(bytes calldata encodedHyMsg) public pure returns (HyMsg memory hyMsg) {
function parseHyMsg(
bytes calldata encodedHyMsg
) public pure returns (HyMsg memory hyMsg) {
uint index = 0;

hyMsg.version = encodedHyMsg.toUint8(index);
Expand All @@ -97,7 +107,10 @@ contract Hyperlane {
}

// Hash the body
bytes memory body = encodedHyMsg.slice(index, encodedHyMsg.length - index);
bytes memory body = encodedHyMsg.slice(
index,
encodedHyMsg.length - index
);
hyMsg.hash = keccak256(abi.encodePacked(keccak256(body)));

// Parse the rest of the message
Expand Down
42 changes: 26 additions & 16 deletions solidity/src/Pragma.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@

pragma solidity ^0.8.0;

import { IPragma, DataFeed } from "./interfaces/IPragma.sol";
import {IPragma, DataFeed} from "./interfaces/IPragma.sol";
import "./PragmaDecoder.sol";
import "./libraries/EventsLib.sol";
import "./libraries/ErrorsLib.sol";

/// @title Pragma
/// @author Pragma Labs
/// @custom:contact security@pragma.build
/// @notice The Pragma contract.
contract Pragma is IPragma {

contract Pragma is IPragma, PragmaDecoder {
/* STORAGE */

address payable public hyperlane;
uint16[] public dataSourceEmitterChainIds;
bytes32[] public dataSourceEmitterAddresses;
uint public validTimePeriodSeconds;
uint public singleUpdateFeeInWei;
mapping(bytes32 => uint64) public latestDataInfoPublishTime;
Expand All @@ -25,20 +23,32 @@ contract Pragma is IPragma {
bytes32[] memory _dataSourceEmitterAddresses,
uint _validTimePeriodSeconds,
uint _singleUpdateFeeInWei
) {
// Initialize the contract.
hyperlane = payable(_hyperlane);
dataSourceEmitterChainIds = _dataSourceEmitterChainIds;
dataSourceEmitterAddresses = _dataSourceEmitterAddresses;
)
PragmaDecoder(
_hyperlane,
_dataSourceEmitterChainIds,
_dataSourceEmitterAddresses
)
{
validTimePeriodSeconds = _validTimePeriodSeconds;
singleUpdateFeeInWei = _singleUpdateFeeInWei;
}

/// @inheritdoc IPragma
function updateDataFeeds(
bytes[] calldata updateData
) external payable {
// Update the data feeds.
function updateDataFeeds(bytes[] calldata updateData) external payable {
uint totalNumUpdates = 0;
uint len = updateData.length;
for (uint i = 0; i < len; ) {
totalNumUpdates += updateDataInfoFromUpdate(updateData[i]);

unchecked {
i++;
}
}
uint requiredFee = getTotalFee(totalNumUpdates);
if (msg.value < requiredFee) {
revert ErrorsLib.InsufficientFee();
}
}

/// @inheritdoc IPragma
Expand Down
Loading

0 comments on commit 1ff5e3b

Please sign in to comment.