Skip to content

Commit

Permalink
Init script and CI
Browse files Browse the repository at this point in the history
  • Loading branch information
antares-sw committed May 24, 2024
1 parent 411c3b9 commit 1d96827
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 0 deletions.
89 changes: 89 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: code coverage

on:
pull_request:
branches:
- main

jobs:
comment-forge-coverage:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- name: Checkout code
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Install foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Run Forge build
run: |
forge --version
forge build --sizes
id: build
- name: Run forge coverage
id: coverage
run: |
{
echo 'COVERAGE<<EOF'
forge coverage | grep '^|' | grep -v 'test/'
echo EOF
} >> "$GITHUB_OUTPUT"
env:
FOUNDRY_RPC_URL: "${{ secrets.RPC_URL }}"

- name: Check coverage is updated
uses: actions/github-script@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const file = "coverage.txt"
if(!fs.existsSync(file)) {
console.log("Nothing to check");
return
}
const currentCoverage = fs.readFileSync(file, "utf8").trim();
const newCoverage = (`${{ steps.coverage.outputs.COVERAGE }}`).trim();
if (newCoverage != currentCoverage) {
core.setFailed(`Code coverage not updated. Run : forge coverage | grep '^|' | grep -v 'test/' > coverage.txt`);
}
- name: Comment on PR
id: comment
uses: actions/github-script@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const {data: comments} = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
})
const botComment = comments.find(comment => comment.user.id === 41898282)
const output = `${{ steps.coverage.outputs.COVERAGE }}`;
const commentBody = `Forge code coverage:\n${output}\n`;
if (botComment) {
github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
})
} else {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: commentBody
});
}
24 changes: 24 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Lint

on:
push:
branches:
- main
pull_request:

jobs:
run-linters:
name: Run linters
runs-on: ubuntu-latest

steps:
- name: Check out Git repository
uses: actions/checkout@v3

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Lint
run: forge fmt --check
41 changes: 41 additions & 0 deletions .github/workflows/tests-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Tests

on:
push:
branches:
- main

jobs:
forge-tests:
name: Forge Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- uses: actions/setup-node@v3
with:
node-version: 16
cache-dependency-path: "./test/js-scripts"
cache: "yarn"

- run: yarn
working-directory: ./test/js-scripts

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Build
run: forge build
env:
FOUNDRY_PROFILE: ci

- name: Run tests
run: forge test --isolate -vvv
env:
FOUNDRY_PROFILE: ci
FORGE_SNAPSHOT_CHECK: true
42 changes: 42 additions & 0 deletions .github/workflows/tests-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Tests

on:
pull_request:
branches:
- main
- dev

jobs:
forge-tests:
name: Forge Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- uses: actions/setup-node@v3
with:
node-version: 16
cache-dependency-path: "./test/js-scripts"
cache: "yarn"

- run: yarn
working-directory: ./test/js-scripts

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Build
run: forge build
env:
FOUNDRY_PROFILE: pr

- name: Run tests
run: forge test --isolate -vvv
env:
FOUNDRY_PROFILE: pr
FORGE_SNAPSHOT_CHECK: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Compiler files
cache/
out/
*node_modules/

# Ignores development broadcast logs
!/broadcast
Expand Down
17 changes: 17 additions & 0 deletions price_updater/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Sepolia
MAINNET_RPC_URL=https://example.com
ARBITRUM_RPC_URL=https://example.com
PRIVATE_KEY=0x2......
TARGET_CHAIN=10003
TARGET_ADDRESS=0x744836a91f5151c6ef730eb7e07c232997debaaa
PRICE_FEED=0x38211b7ed71fa91fd65b69b6bf2c02efe60fc35b
PRICE_FEED_SENDER=0xe572a8631a49ec4c334812bb692beecf934ac4e9

# Mainnet
MAINNET_RPC_URL=https://example.com
ARBITRUM_RPC_URL=https://example.com
PRIVATE_KEY=0x2......
TARGET_CHAIN=23
TARGET_ADDRESS=0xbd335c16c94be8c4dd073ae376ddf78bec1858df
PRICE_FEED=0xba74737a078c05500dd98c970909e4a3b90c35c6
PRICE_FEED_SENDER=0xf7d4e7273e5015c96728a6b02f31c505ee184603
39 changes: 39 additions & 0 deletions price_updater/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
aiohttp==3.9.5
aiosignal==1.3.1
attrs==23.2.0
bitarray==2.9.2
certifi==2024.2.2
charset-normalizer==3.3.2
ckzg==1.0.2
cytoolz==0.12.3
eth-account==0.11.2
eth-hash==0.7.0
eth-keyfile==0.8.1
eth-keys==0.5.1
eth-rlp==1.0.1
eth-typing==4.2.3
eth-utils==4.1.1
eth_abi==5.1.0
frozenlist==1.4.1
hexbytes==0.3.1
idna==3.7
jsonschema==4.22.0
jsonschema-specifications==2023.12.1
lru-dict==1.2.0
multidict==6.0.5
parsimonious==0.10.0
protobuf==5.27.0
pycryptodome==3.20.0
python-dotenv==1.0.1
pyunormalize==15.1.0
referencing==0.35.1
regex==2024.5.15
requests==2.32.2
rlp==4.0.1
rpds-py==0.18.1
toolz==0.12.1
typing_extensions==4.12.0
urllib3==2.2.1
web3==6.19.0
websockets==12.0
yarl==1.9.4
63 changes: 63 additions & 0 deletions price_updater/update_price.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import os
import time
from web3 import Web3
from dotenv import load_dotenv

load_dotenv()

TWELVE_HOURS = 12 * 60 * 60

MAINNET_PROVIDER = Web3(Web3.HTTPProvider(os.getenv("MAINNET_RPC_URL")))
ARBITRUM_PROVIDER = Web3(Web3.HTTPProvider(os.getenv("ARBITRUM_RPC_URL")))
PRIVATE_KEY = os.getenv("PRIVATE_KEY")
ACCOUNT = MAINNET_PROVIDER.eth.account.from_key(PRIVATE_KEY)
ACCOUNT_ADDRESS = ACCOUNT.address

price_feed_abi = [
{"constant": True, "inputs": [], "name": "latestTimestamp", "outputs": [{"name": "", "type": "uint256"}], "payable": False, "stateMutability": "view", "type": "function"},
{"constant": False, "inputs": [{"name": "targetChain", "type": "uint16"}, {"name": "targetAddress", "type": "address"}], "name": "syncRate", "outputs": [], "payable": True, "stateMutability": "payable", "type": "function"},
{"constant": True, "inputs": [{"name": "targetChain", "type": "uint16"}], "name": "quoteRateSync", "outputs": [{"name": "cost", "type": "uint256"}], "payable": False, "stateMutability": "view", "type": "function"},
]

price_feed_address = Web3.to_checksum_address(os.getenv("PRICE_FEED")) # Mainnet
price_feed_sender_address = Web3.to_checksum_address(os.getenv("PRICE_FEED_SENDER")) # Mainnet
target_chain = int(os.getenv("TARGET_CHAIN"))
target_address = Web3.to_checksum_address(os.getenv("TARGET_ADDRESS")) # Arbitrum

def check_and_sync():
price_feed = MAINNET_PROVIDER.eth.contract(address=price_feed_address, abi=price_feed_abi)
price_feed_sender = MAINNET_PROVIDER.eth.contract(address=price_feed_sender_address, abi=price_feed_abi)

# Step 1: Check latest timestamp
latest_timestamp = price_feed.functions.latestTimestamp().call()
current_time = int(time.time())

if current_time - latest_timestamp < TWELVE_HOURS:
print("Less than 12 hours since the last update. No action needed.")
return

# Step 2: Get the cost
current_rate = price_feed_sender.functions.quoteRateSync(target_chain).call()

# Step 3: Sync the rate
tx = price_feed_sender.functions.syncRate(target_chain, target_address).build_transaction({
'chainId': 1, # Mainnet
'gas': 200000,
'gasPrice': Web3.to_wei('20', 'gwei'),
'nonce': MAINNET_PROVIDER.eth.get_transaction_count(ACCOUNT.address),
'value': current_rate
})

signed_tx = ACCOUNT.sign_transaction(tx)
tx_hash = MAINNET_PROVIDER.eth.send_raw_transaction(signed_tx.rawTransaction)

print(f"Sync transaction sent: {tx_hash.hex()}")
receipt = MAINNET_PROVIDER.eth.wait_for_transaction_receipt(tx_hash)
print("Sync transaction confirmed.")

if __name__ == "__main__":
try:
check_and_sync()
except Exception as e:
print(f"Error in check_and_sync: {e}")
exit(1)

0 comments on commit 1d96827

Please sign in to comment.