Skip to content

Commit

Permalink
Merge pull request #10 from xaya/use-foundry
Browse files Browse the repository at this point in the history
Use Foundry instead of Truffle
  • Loading branch information
domob1812 committed Oct 19, 2024
2 parents c2dd9ec + 57a74c7 commit 06bb07e
Show file tree
Hide file tree
Showing 32 changed files with 315 additions and 292 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ libtool
ltmain.sh
m4
missing
node_modules
package-lock.json
py-compile
stamp-h1
test-driver
Expand Down
15 changes: 15 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[submodule "eth/solidity/lib/polygon-contract"]
path = eth/solidity/lib/polygon-contract
url = https://github.com/xaya/polygon-contract
[submodule "eth/solidity/lib/openzeppelin-contracts"]
path = eth/solidity/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "eth/solidity/lib/base64"]
path = eth/solidity/lib/base64
url = https://github.com/Brechtpd/base64
[submodule "eth/solidity/lib/wchi"]
path = eth/solidity/lib/wchi
url = https://github.com/xaya/wchi
[submodule "eth/solidity/lib/forge-std"]
path = eth/solidity/lib/forge-std
url = https://github.com/foundry-rs/forge-std
2 changes: 0 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -Im4

SUBDIRS = src xayax xayacore eth

EXTRA_DIST = node_modules
35 changes: 20 additions & 15 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,32 @@
# libxayagame directly, it depends on libxayautil and many of the same base
# packages like SQLite or libjson-rpc-cpp, so that reusing them for the
# build from the existing package makes sense.
FROM xaya/libxayagame AS build
RUN apk add --no-cache \
#
# It seems very hard to get the pre-built foundry binaries to run on Alpine,
# so we base the image on Ubuntu instead.
FROM xaya/libxayagame:ubuntu AS build
RUN apt update && apt -y install \
autoconf \
autoconf-archive \
automake \
boost-dev \
build-base \
ca-certificates \
libboost-all-dev \
build-essential \
cmake \
curl \
git \
gflags-dev \
libgflags-dev \
libtool \
mariadb-dev \
npm \
pkgconfig \
py3-pip \
libmariadb-dev \
pkg-config \
python3-pip \
python3-dev
RUN pip3 install --break-system-packages web3
RUN npm install -g truffle
RUN pip3 install web3

# Install Foundry. It seems pretty hard to get "foundryup" to run inside
# Docker, so we just download and manually install a specific release.
ARG FOUNDRY_RELEASE="nightly-adb6abae69c7a0d766db123f66686cc890c22dd0"
WORKDIR /usr/local/bin
RUN curl -L "https://github.com/foundry-rs/foundry/releases/download/${FOUNDRY_RELEASE}/foundry_nightly_linux_amd64.tar.gz" | tar zxv

# Build and install libunivalue.
ARG UNIVALUE_VERSION="v1.0.5"
Expand Down Expand Up @@ -51,8 +58,6 @@ RUN ./autogen.sh && ./configure && make && make install-strip
WORKDIR /usr/src/xayax
COPY . .
RUN make distclean || true
RUN npm install
RUN ln -s ../../node_modules eth/solidity/node_modules
RUN ./autogen.sh && ./configure
# Build the solidity contracts first, so that they are already
# available for the python script that generates contract-constants.cpp.
Expand All @@ -70,7 +75,7 @@ RUN for b in /usr/local/bin/xayax-*; \
COPY docker/entrypoint.sh bin/

# Construct the final image.
FROM alpine
FROM ubuntu:22.04
COPY --from=build /jail /usr/local/
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
LABEL description="Xaya X connector binaries"
Expand Down
2 changes: 1 addition & 1 deletion docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh -e
#!/bin/bash -e

# If no HOST is explicitly set, try to detect it automatically.
if [[ -z $HOST ]]
Expand Down
4 changes: 4 additions & 0 deletions eth/ethchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ const std::map<int64_t, std::string> CHAIN_IDS =
{137, "polygon"},
{80'001, "mumbai"},
{1'337, "ganache"},
/* This is anvil from Foundry, but in essence does the same as ganache
(i.e. local regtest-like testing on EVM chains). Which it is does not
matter from the game's point of view. */
{31'337, "ganache"},
};

/**
Expand Down
19 changes: 11 additions & 8 deletions eth/gen-contract-constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ def genSignature (abi, typ, name):
i["type"] for i in inp
]) + ")"

def contractPath (nm):
"""
Returns the path of the contract build artefact.
"""

return os.path.join ("solidity", "out", f"{nm}.sol", f"{nm}.json")

# Load the XayaAccounts ABI to generate signature hashes.
with open (os.path.join ("solidity", "node_modules", "@xaya",
"eth-account-registry", "build", "contracts",
"XayaAccounts.json")) as f:
with open (contractPath ("XayaAccounts"), "rt") as f:
accAbi = json.load (f)["abi"]
sgn = genSignature (accAbi, "event", "Move")
print ("const std::string MOVE_EVENT = \""
Expand All @@ -63,17 +68,15 @@ def outputFcnSelector (abi, name, var):
+ hexWithPrefix (Web3.keccak (sgn.encode ("ascii"))[:4])
+ "\";")
outputFcnSelector (accAbi, "wchiToken", "ACCOUNT_WCHI_FCN")
with open (os.path.join ("solidity", "build", "contracts",
"CallForwarder.json")) as f:
with open (contractPath ("CallForwarder"), "rt") as f:
abi = json.load (f)["abi"]
outputFcnSelector (abi, "execute", "FORWARDER_EXECUTE_FCN")

# Store the deploying bytecode for our overlay contracts.
def outputContract (name, var):
with open (os.path.join ("solidity", "build", "contracts",
f"{name}.json")) as f:
with open (contractPath (name), "rt") as f:
data = json.load (f)
print (f"const std::string {var} = \"{data['bytecode']}\";")
print (f"const std::string {var} = \"{data['bytecode']['object']}\";")
outputContract ("CallForwarder", "CALL_FORWARDER_CODE")
outputContract ("TrackingAccounts", "TRACKING_ACCOUNTS_CODE")

Expand Down
1 change: 1 addition & 0 deletions eth/pending.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ PendingDataExtractor::GetMoves (EthRpcClient& rpc,
possible, while returning any move events generated. */
Json::Value tx(Json::objectValue);
tx["to"] = from.GetChecksummed ();
tx["from"] = from.GetChecksummed ();
tx["value"] = data["value"];
tx["data"] = AbiEncoder::ConcatHex (FORWARDER_EXECUTE_FCN,
execArgs.Finalise ());
Expand Down
3 changes: 2 additions & 1 deletion eth/solidity/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build
cache
out
6 changes: 3 additions & 3 deletions eth/solidity/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
all-local:
truffle compile
forge build

check-local:
truffle test
forge test

clean-local:
rm -rf build
rm -rf cache out
6 changes: 6 additions & 0 deletions eth/solidity/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 1_000
1 change: 1 addition & 0 deletions eth/solidity/lib/base64
Submodule base64 added at dcbf85
1 change: 1 addition & 0 deletions eth/solidity/lib/forge-std
Submodule forge-std added at 1de6ee
1 change: 1 addition & 0 deletions eth/solidity/lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at dc44c9
1 change: 1 addition & 0 deletions eth/solidity/lib/polygon-contract
Submodule polygon-contract added at ddca99
1 change: 1 addition & 0 deletions eth/solidity/lib/wchi
Submodule wchi added at a68ca6
1 change: 0 additions & 1 deletion eth/solidity/node_modules

This file was deleted.

4 changes: 4 additions & 0 deletions eth/solidity/remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
base64-sol/=lib/base64/
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@xaya/eth-account-registry/contracts/=lib/polygon-contract/contracts/
@xaya/wchi/contracts/=lib/wchi/contracts/
9 changes: 9 additions & 0 deletions eth/solidity/src/BuildWCHI.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
// Copyright (C) 2024 The Xaya developers

pragma solidity ^0.7.6;

/* This file is here just to force Forge to build the WCHI contract,
which is used for the Python testing package. */

import "@xaya/wchi/contracts/WCHI.sol";
11 changes: 11 additions & 0 deletions eth/solidity/src/BuildXayaPolicy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
// Copyright (C) 2024 The Xaya developers

pragma solidity ^0.8.4;

/* This file is here just to force Forge to build the XayaPolicy and NftMetadata
contracts, too, whose build artefacts we need for the Python testing
package. */

import "@xaya/eth-account-registry/contracts/NftMetadata.sol";
import "@xaya/eth-account-registry/contracts/XayaPolicy.sol";
File renamed without changes.
File renamed without changes.
140 changes: 140 additions & 0 deletions eth/solidity/test/MoveTracking.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: MIT
// Copyright (C) 2021-2024 The Xaya developers

pragma solidity ^0.8.4;

import "./MultiMover.sol";
import "./TestToken.sol";
import "../src/CallForwarder.sol";
import "../src/TrackingAccounts.sol";

import "@xaya/eth-account-registry/contracts/TestPolicy.sol";

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { Test } from "forge-std/Test.sol";

/**
* @dev Unit tests for call forwarding and tracking moves with the
* instrumentation contracts.
*/
contract MoveTrackingTest is Test
{

address public constant operator = address (1);

IERC20 public wchi;

TrackingAccounts public xa;
CallForwarder public fwd;
MultiMover public mover;

function setUp () public
{
wchi = new TestToken (operator, 78e6 * 1e8);
IXayaPolicy policy = new TestPolicy ();

vm.startPrank (operator);
xa = new TrackingAccounts (wchi);
xa.schedulePolicyChange (policy);
vm.warp (xa.policyTimelock () + 1);
xa.enactPolicyChange ();
vm.stopPrank ();

fwd = new CallForwarder (xa);
mover = new MultiMover (xa);

/* The TestPolicy imposes a WCHI fee for moves, so we need to make sure that
the fwd contract has WCHI and the necessary approvals. */
vm.startPrank (operator);
wchi.transfer (address (fwd), 1e8);
wchi.transfer (address (mover), 1e8);
vm.startPrank (address (fwd));
wchi.approve (address (xa), type (uint256).max);
wchi.approve (address (mover), type (uint256).max);
xa.setApprovalForAll (address (mover), true);
vm.stopPrank ();

/* The test name is owned by the fwd contract, and can thus be moved
by a forwarded call. */
vm.prank (address (fwd));
xa.register ("p", "test");
}

function test_trackDirectMoves () public
{
TrackingAccounts.MoveData[] memory res = fwd.execute (address (xa),
abi.encodeWithSelector (TrackingAccounts.move.selector,
"p", "test", "x", type (uint256).max, 0, address (0)));
assertEq (res.length, 1);
assertEq (res[0].ns, "p");
assertEq (res[0].name, "test");
assertEq (res[0].move, "x");
assertEq (res[0].nonce, 0);
assertEq (res[0].mover, address (fwd));
assertEq (res[0].amount, 0);
assertEq (res[0].receiver, address (0));

res = fwd.execute (address (xa),
abi.encodeWithSelector (TrackingAccounts.move.selector,
"p", "test", "y", type (uint256).max, 0, address (0)));
assertEq (res.length, 1);
assertEq (res[0].move, "y");
assertEq (res[0].nonce, 1);
}

function test_revertingMove () public
{
vm.expectRevert ();
fwd.execute (address (xa),
abi.encodeWithSelector (TrackingAccounts.move.selector,
"p", "test", "", type (uint256).max, 0, address (0)));
}

function test_moveWithChiPayment () public
{
address to = address (2);
TrackingAccounts.MoveData[] memory res = fwd.execute (address (xa),
abi.encodeWithSelector (TrackingAccounts.move.selector,
"p", "test", "x", type (uint256).max, 42, to));
assertEq (res.length, 1);
assertEq (res[0].amount, 42);
assertEq (res[0].receiver, to);
assertEq (wchi.balanceOf (to), 42);
}

function test_multipleMoves () public
{
string[] memory ns = new string[] (1);
ns[0] = "p";
string[] memory name = new string[] (1);
name[0] = "test";
string[] memory values = new string[] (2);
values[0] = "x";
values[1] = "y";

TrackingAccounts.MoveData[] memory res = fwd.execute (address (mover),
abi.encodeWithSelector (MultiMover.send.selector, ns, name, values));
assertEq (res.length, 2);
assertEq (res[0].move, "x");
assertEq (res[0].nonce, 0);
assertEq (res[1].move, "y");
assertEq (res[1].nonce, 1);
}

function test_ethPayment () public
{
bytes memory inner = abi.encodeWithSelector (MultiMover.requireEth.selector,
"p", "test", "x");
(bool sent, bytes memory data) = address (fwd).call {value: 20} (
abi.encodeWithSelector (CallForwarder.execute.selector,
address (mover), inner));
assertTrue (sent);

TrackingAccounts.MoveData[] memory res
= abi.decode (data, (TrackingAccounts.MoveData[]));
assertEq (res.length, 1);
assertEq (res[0].move, "x");
}

}
File renamed without changes.
21 changes: 21 additions & 0 deletions eth/solidity/test/TestToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
// Copyright (C) 2024 The Xaya developers

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
* @dev Simple test token (representing WCHI) that just mints all the
* supply to a given address.
*/
contract TestToken is ERC20
{

constructor (address holder, uint supply)
ERC20 ("Wrapped CHI", "WCHI")
{
_mint (holder, supply);
}

}
Loading

0 comments on commit 06bb07e

Please sign in to comment.