Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nihat99 authored Jan 2, 2025
0 parents commit ac8c1fb
Show file tree
Hide file tree
Showing 71 changed files with 13,628 additions and 0 deletions.
Empty file added .cache/.gitkeep
Empty file.
54 changes: 54 additions & 0 deletions .github/workflows/ci-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: CI Tests

on:
workflow_dispatch:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

jobs:
build:
if: github.repository == 'Nodeguardians/ng-questplay'
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
node-version: [16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v3
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Install Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: "2.3.1"
- name: Install Nargo
uses: noir-lang/[email protected]
with:
toolchain: 0.19.2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Configure git
run: |
git checkout -b new-branch
git config user.name "someone"
git config user.email "[email protected]"
- name: Install dependencies
run: |
npm run start-adventure
git commit -a -m "Install dependencies"
- name: Create .env file
run: |
touch .env
echo GITHUB_TOKEN="${{ secrets.PUBLIC_TOKEN }}" >> .env
- run: npm run test
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
**/node_modules
.openzeppelin
.DS_Store
.vscode
artifacts
cache
.env
.cache/*.jwt
.settings

artifacts
cache

target

Prover.toml
Verifier.toml
crs
13 changes: 13 additions & 0 deletions @ngquests/contracts/BridgeRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

contract BridgeRegistry {

mapping(bytes32 => bool) public bridgeHashes;

function registerMessage(bytes calldata _message) external returns (bytes32 bridgeHash) {
bridgeHash = keccak256(abi.encode(msg.sender, _message));
bridgeHashes[bridgeHash] = true;
}

}
21 changes: 21 additions & 0 deletions @ngquests/contracts/IValidator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

interface IValidator {

/// @dev Returns address of contract belonging to `user` in part `k` of quest.
function deployments(address user, uint k) external view returns (address);


/// @dev Deploys CTF contract for user to interact with.
function deploy(uint k) external;


/// @dev Tests whether contract belonging to `user` in part `k` has been "captured".
/// Returns true if contract "captured", false otherwise.
function test(address user, uint k) external view returns (bool);

/// @dev Returns name of contract to be deployed for part `k`.
function contractName(uint k) external pure returns (string memory);

}
70 changes: 70 additions & 0 deletions @ngquests/contracts/SingleTokenFlashLender.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";

contract SingleTokenFlashLender is IERC3156FlashLender {

bytes32 constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");

IERC20 public immutable token;

constructor(IERC20 _token) {
token = _token;
}

function maxFlashLoan(
address _token
) public view returns (uint256) {

if (_token != address(token)) {
return 0;
}

return token.balanceOf(address(this));

}

function flashFee(
address _token,
uint256 /*amount*/
) external view returns (uint256) {
require(_token != address(token), "FlashLender: Unsupported currency");

return 0; // This flash loan is free!
}

function flashLoan(
IERC3156FlashBorrower receiver,
address _token,
uint256 _amount,
bytes calldata _data
) external returns (bool) {

require(address(token) == _token, "FlashLender: Unsupported currency");

bool transferResult = token.transfer(address(receiver), _amount);
require(transferResult, "FlashLender: Transfer failed");

bytes32 callBackResult = receiver.onFlashLoan(
msg.sender,
_token,
_amount,
0,
_data
);
require(callBackResult == CALLBACK_SUCCESS, "FlashLender: Callback failed");

bool repayResult = token.transferFrom(
address(receiver),
address(this),
_amount
);
require(repayResult, "FlashLender: Repay failed");

return true;

}

}
48 changes: 48 additions & 0 deletions @ngquests/contracts/Token.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

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

/// @dev Test token with minting capabilities
/// Clone-friendly for cheaper gas in CTF quests
contract Token is ERC20 {

string private _name;
string private _symbol;

address private owner;
bool private isInitialized;

modifier onlyOwner() {
require(msg.sender == owner, "Caller is not owner");
_;
}

constructor() ERC20("", "") { }

function initialize(
string memory name_,
string memory symbol_
) external {
require(!isInitialized, "Token already initialized");

_name = name_;
_symbol = symbol_;

owner = msg.sender;
isInitialized = true;
}

function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}

function name() public view override returns (string memory) {
return _name;
}

function symbol() public view override returns (string memory) {
return _symbol;
}

}
11 changes: 11 additions & 0 deletions @ngquests/contracts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "@ngquests/contracts",
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"No test specified\""
},
"author": "",
"license": "MIT"
}
8 changes: 8 additions & 0 deletions @ngquests/test-helpers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
get matchers () { return require('./src/matchers.js'); },
get events () { return require('./src/events.js'); },
get diamonds () { return require('./src/diamonds.js'); },
get ast () { return require('./src/ast.js'); },
get cheating () { return require('./src/cheating.js'); },
get FoundryReport () { return require('./src/FoundryReport.js'); }
}
13 changes: 13 additions & 0 deletions @ngquests/test-helpers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@ngquests/test-helpers",
"version": "0.1.0",
"description": "",
"main": "index.js",
"author": "",
"license": "MIT",
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^1.0.4",
"@nomiclabs/hardhat-ethers": "^2.2.1",
"chai-exclude": "^2.1.0"
}
}
118 changes: 118 additions & 0 deletions @ngquests/test-helpers/src/FoundryReport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
const chalk = require('chalk');

const CHECKMARK = chalk.green("\u2714");
const X = chalk.red("\u2718")

const isStandardName = new RegExp(/.*.[1-9]+.t.sol$/);

function indent(i) {
return " ".repeat(i);
}

const sleep = (ms) => {
return new Promise((resolve, _) => setTimeout(resolve, ms));
};

function suiteCmp(suite1, suite2) {

const index1 = suite1.match(/(?<=Part )[1-9]+/);
const index2 = suite2.match(/(?<=Part )[1-9]+/);

if (index1 == null) return 1;
else if (index2 == null) return -1;

return index1[0].localeCompare(index2[0]);
}

class FoundryReport {

constructor(jsonResults) {
this.passCount = 0;
this.failCount = 0;
this.results = {};
this.failLogs = [];
for (const suiteName in jsonResults) {

const [suiteTitle, subsuiteName] = this.#parseSuiteName(suiteName)

if (!(suiteTitle in this.results)) {
this.results[suiteTitle] = [];
}

const testResults = Object.entries(
jsonResults[suiteName].test_results
).map(([name, details]) => this.#parseTestResults(name, details));

this.results[suiteTitle].push({
name: subsuiteName,
testResults: testResults
});

}
}

async print(delay=0) {

// Suites sorted by part
const suitesByPart = Object.keys(this.results).sort(suiteCmp);

for (const suiteName of suitesByPart) {
console.log('\n' + indent(1) + suiteName);
for (const subsuite of this.results[suiteName]) {
console.log(indent(2) + subsuite.name);
for (const result of subsuite.testResults) {
await sleep(delay);
console.log(indent(3) + result);
}
}
}

console.log();
console.log(chalk.green(`${indent(1)}${this.passCount} passing`));
if (this.failCount > 0) {
console.log(chalk.red(`${indent(1)}${this.failCount} failing`));
}
console.log();

}

// "test/foundry/{PartName}.{PartIndex}.t.sol:{TestContractName}"
// "test/foundry/private/{PartName}.{PartIndex}.t.sol:{TestContractName}"
#parseSuiteName(foundrySuiteTitle) {
const folderNames = foundrySuiteTitle.split("/");
const isPrivate = (folderNames[2] == "private");

const [ fileName, contractName ] = folderNames[folderNames.length - 1].split(":");

let [ mainName, partIndex ] = fileName.split(".");
mainName = mainName.replace(/([A-Z])/g, " $1").slice(1);
const subsuiteName = contractName.replace(/([A-Z0-9])/g, " $1").slice(1);

if (!isStandardName.test(fileName)) {
// For non-standard names, just return the full suite name
return [mainName, subsuiteName];
}

const suiteTitle = isPrivate
? `${mainName} (Part ${partIndex}: Private)`
: `${mainName} (Part ${partIndex})`;

return [suiteTitle, subsuiteName];
}

#parseTestResults(testName, testDetails) {
testName = testName.replace(/_/g, ' ').slice(0, -2);
testName = testName[0].toUpperCase() + testName.slice(1);

if (testDetails.success) {
this.passCount++;
return `${CHECKMARK} ${chalk.grey(testName)}`;
} else {
this.failCount++;
return chalk.red(`${X} ${testName} <--- ${testDetails.decoded_logs[0]}`);
}
}

}

module.exports = FoundryReport;
Loading

0 comments on commit ac8c1fb

Please sign in to comment.