Basic deploy script
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 30s Details

This commit is contained in:
Ladd Hoffman 2024-03-06 16:50:59 -06:00
parent 20a4aab2a6
commit 9c969ee56c
35 changed files with 522 additions and 4966 deletions

View File

View File

@ -1,21 +0,0 @@
module.exports = {
root: true,
env: { es2020: true },
extends: [
'eslint:recommended',
'airbnb',
],
ignorePatterns: ['.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
rules: {
'no-console': 'off',
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": false,
"optionalDependencies": false,
"peerDependencies": false,
}
]
}
}

2
backend/.gitignore vendored
View File

@ -1,2 +0,0 @@
node_modules/
.env

View File

@ -1,9 +0,0 @@
FROM node
WORKDIR /app
ADD package.json package-lock.json index.js /app/
RUN npm ci
ENTRYPOINT ["node", "index.js"]

View File

@ -1,8 +0,0 @@
version: "3"
services:
backend:
build: .
restart: always
ports:
- "3002:3000"

View File

@ -1,40 +0,0 @@
const express = require('express');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3000;
const {
CasperClient, DeployUtil, Contracts: { Contract },
} = require('casper-js-sdk');
const RPC_API = 'http://65.109.56.30:7777/rpc';
const casperClient = new CasperClient(RPC_API);
const contract = new Contract(casperClient);
contract.setContractHash('hash-9d6641378c5859e4a0367b37f358d9861496318ba814bdd92903210a3f633198');
app.use(express.json());
app.post('/sendDeploy', async (req, res) => {
const { body: deployJson } = req;
const deploy = DeployUtil.deployFromJson(deployJson).unwrap();
const deployHash = await casperClient.putDeploy(deploy);
res.status(200).send(`Deploy hash: ${deployHash}`);
});
app.get('/queryMessage', async (req, res) => {
const result = await contract.queryContractData(['message']);
console.log('query result:', result);
res.send(result);
});
app.get('*', (req, res) => {
console.log(`req.path: ${req.path}`);
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});

4003
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.7",
"casper-js-sdk": "^2.15.4",
"dotenv": "^16.4.5",
"express": "^4.18.2"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0"
}
}

797
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,9 +11,10 @@
},
"dependencies": {
"axios": "^1.6.7",
"casper-js-sdk": "^2.15.4",
"backend": "file://../backend",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"web3": "^4.5.0"
},
"devDependencies": {
"@types/react": "^18.2.56",

View File

@ -1,7 +1,8 @@
import { useState } from 'react';
import Connect from './Connect';
import UpdateMessage from './UpdateMessage';
import Query from './Query';
import QueryMessage from './QueryMessage';
import QueryRepBalance from './QueryRepBalance';
import './App.css';
function App() {
@ -17,7 +18,9 @@ function App() {
{publicKey}
<br />
<UpdateMessage publicKey={publicKey} />
<Query publicKey={publicKey} />
<QueryMessage />
<br />
<QueryRepBalance publicKey={publicKey} />
</>
)}
</div>

View File

@ -1,20 +0,0 @@
import axios from 'axios';
import { CLPublicKey } from 'casper-js-sdk';
const query = (props) => {
const accountHash = CLPublicKey.fromHex(props.publicKey).toAccountHashStr().substring(13);
axios
.get(`/api/queryMessage?accountHash=${accountHash}`)
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
};
function Query(props) {
return <button type="button" onClick={() => query(props)}>Query</button>;
}
export default Query;

View File

@ -0,0 +1,18 @@
import axios from 'axios';
const queryMessage = () => {
axios
.get('/api/queryMessage')
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
};
function QueryMessage(props) {
return <button type="button" onClick={() => queryMessage(props)}>Query Message</button>;
}
export default QueryMessage;

View File

@ -0,0 +1,22 @@
import axios from 'axios';
import { CLPublicKey, CLValueParsers, encodeBase64 } from 'casper-js-sdk';
const queryRepBalance = (props) => {
const accountKeyBytes = CLValueParsers.toBytes(CLPublicKey.fromHex(props.publicKey)).unwrap();
console.log('accountKeyBytes', accountKeyBytes);
const b64accountKey = encodeBase64(accountKeyBytes);
axios
.get(`/api/repBalance?account=${b64accountKey}`)
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
};
function QueryRepBalance(props) {
return <button type="button" onClick={() => queryRepBalance(props)}>Query REP Balance</button>;
}
export default QueryRepBalance;

View File

@ -3,24 +3,22 @@ import {
Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey, DeployUtil,
} from 'casper-js-sdk';
import axios from 'axios';
import { contracts, networkName } from 'backend/src/config';
import getProvider from './casper-wallet';
const provider = getProvider();
const NETWORK_NAME = 'casper-test'; // "casper" for mainnet
const CONTRACT_HASH = 'hash-9d6641378c5859e4a0367b37f358d9861496318ba814bdd92903210a3f633198';
const updateMessage = (props, message) => {
const contract = new Contracts.Contract();
contract.setContractHash(CONTRACT_HASH);
contract.setContractHash(contracts.availability);
const runtimeArguments = RuntimeArgs.fromMap({
message: CLValueBuilder.string(message),
});
const deploy = contract.callEntrypoint(
'hello',
'list_append',
runtimeArguments,
CLPublicKey.fromHex(props.publicKey),
NETWORK_NAME,
networkName,
'1000000000', // 1 CSPR (10^9 Motes)
);
const deployJSON = DeployUtil.deployToJson(deploy);

View File

@ -1,3 +0,0 @@
Cargo.lock
tests/wasm
target/

View File

@ -1,11 +0,0 @@
[workspace]
members = [
"validation-pool",
"availability",
"work-1",
]
resolver = "2"
[profile.release]
codegen-units = 1
lto = true

View File

@ -1,54 +0,0 @@
PINNED_TOOLCHAIN := $(shell cat rust-toolchain)
prepare:
rustup target add wasm32-unknown-unknown
rustup component add clippy --toolchain ${PINNED_TOOLCHAIN}
rustup component add rustfmt --toolchain ${PINNED_TOOLCHAIN}
.PHONY: build-contract
build-availability:
cargo build --release --target wasm32-unknown-unknown -p availability
wasm-strip target/wasm32-unknown-unknown/release/availability.wasm
build-contract:
cargo build --release --target wasm32-unknown-unknown -p validation-pool
cargo build --release --target wasm32-unknown-unknown -p availability
cargo build --release --target wasm32-unknown-unknown -p work-1
wasm-strip target/wasm32-unknown-unknown/release/validation_pool.wasm
wasm-strip target/wasm32-unknown-unknown/release/availability.wasm
wasm-strip target/wasm32-unknown-unknown/release/work_1.wasm
setup-test: build-contract
mkdir -p tests/wasm
cp ./target/wasm32-unknown-unknown/release/validation_pool.wasm tests/wasm
cp ./target/wasm32-unknown-unknown/release/availability.wasm tests/wasm
cp ./target/wasm32-unknown-unknown/release/work_1.wasm tests/wasm
test: setup-test
cd tests && cargo test
clippy:
cd validation-pool && cargo clippy --all-targets -- -D warnings
cd availability && cargo clippy --all-targets -- -D warnings
cd work-1 && cargo clippy --all-targets -- -D warnings
cd tests && cargo clippy --all-targets -- -D warnings
check-lint: clippy
cd validation_pool && cargo fmt -- --check
cd availability && cargo fmt -- --check
cd work-1 && cargo fmt -- --check
cd tests && cargo fmt -- --check
lint: clippy
cd validation-pool && cargo fmt
cd availability && cargo fmt
cd work-1 && cargo fmt
cd tests && cargo fmt
clean:
cd validation-pool && cargo clean
cd availability && cargo clean
cd work-1 && cargo clean
cd tests && cargo clean
rm -rf tests/wasm

View File

@ -1,16 +0,0 @@
[package]
name = "availability"
version = "0.1.0"
edition = "2021"
description = "Contract that receives reputation stakes from a worker and makes them available to one or more work contracts"
[dependencies]
casper-contract = "4.0.0"
casper-types = "4.0.1"
[[bin]]
name = "availability"
path = "src/main.rs"
bench = false
doctest = false
test = false

View File

@ -1,10 +0,0 @@
// Parameter names
pub const AMOUNT: &str = "amount";
pub const WORK_CONTRACT: &str = "work_contract";
pub const WORKER: &str = "worker";
// Entry point names
pub const STAKE_AVAILABILITY_ENTRY_POINT_NAME: &str = "stake_availability";
pub const ASSIGN_WORK_ENTRY_POINT_NAME: &str = "assign_work";
pub const GET_ASSIGNED_WORK_ENTRY_POINT_NAME: &str = "assign_work";

View File

@ -1,76 +0,0 @@
//! Entry points
use alloc::{string::String, vec, vec::Vec};
use casper_types::{
CLType, CLTyped, EntryPoint, EntryPointAccess, EntryPointType, EntryPoints, Key, Parameter,
U256,
};
use crate::constants::{
AMOUNT, ASSIGN_WORK_ENTRY_POINT_NAME, GET_ASSIGNED_WORK_ENTRY_POINT_NAME,
STAKE_AVAILABILITY_ENTRY_POINT_NAME, WORKER, WORK_CONTRACT,
};
pub fn hello() -> EntryPoint {
EntryPoint::new(
String::from("hello"),
vec![Parameter::new("message", String::cl_type())],
String::cl_type(),
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
pub fn query() -> EntryPoint {
EntryPoint::new(
String::from("query"),
Vec::new(),
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
// Entry point: Stake availability toward one or more work contracts
pub fn stake_availability() -> EntryPoint {
EntryPoint::new(
String::from(STAKE_AVAILABILITY_ENTRY_POINT_NAME),
vec![Parameter::new(AMOUNT, U256::cl_type())],
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
// Entry point: Assign work to an available worker
pub fn assign_work() -> EntryPoint {
EntryPoint::new(
String::from(ASSIGN_WORK_ENTRY_POINT_NAME),
vec![Parameter::new(WORK_CONTRACT, Key::cl_type())],
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
// Entry point: Get assigned work
pub fn get_assigned_work() -> EntryPoint {
EntryPoint::new(
String::from(GET_ASSIGNED_WORK_ENTRY_POINT_NAME),
vec![Parameter::new(WORKER, Key::cl_type())],
Key::cl_type(),
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
pub fn generate_entry_points() -> EntryPoints {
let mut entry_points = EntryPoints::new();
entry_points.add_entry_point(hello());
entry_points.add_entry_point(query());
// entry_points.add_entry_point(stake_availability());
// entry_points.add_entry_point(assign_work());
// entry_points.add_entry_point(get_assigned_work());
entry_points
}

View File

@ -1,56 +0,0 @@
use casper_types::ApiError;
/// Errors that the contract can return.
///
/// When an `Error` is returned from a smart contract, it is converted to an [`ApiError::User`].
///
/// While the code consuming this contract needs to define further error variants, it can
/// return those via the [`Error::User`] variant or equivalently via the [`ApiError::User`]
/// variant.
#[repr(u16)]
#[derive(Clone, Copy)]
pub enum AvailabilityError {
/// CEP-18 contract called from within an invalid context.
InvalidContext = 60000,
/// Spender does not have enough balance.
InsufficientBalance = 60001,
/// Spender does not have enough allowance approved.
InsufficientAllowance = 60002,
/// Operation would cause an integer overflow.
Overflow = 60003,
/// A required package hash was not specified.
PackageHashMissing = 60004,
/// The package hash specified does not represent a package.
PackageHashNotPackage = 60005,
/// An invalid event mode was specified.
InvalidEventsMode = 60006,
/// The event mode required was not specified.
MissingEventsMode = 60007,
/// An unknown error occurred.
Phantom = 60008,
/// Failed to read the runtime arguments provided.
FailedToGetArgBytes = 60009,
/// The caller does not have sufficient security access.
InsufficientRights = 60010,
/// The list of Admin accounts provided is invalid.
InvalidAdminList = 60011,
/// The list of accounts that can mint tokens is invalid.
InvalidMinterList = 60012,
/// The list of accounts with no access rights is invalid.
InvalidNoneList = 60013,
/// The flag to enable the mint and burn mode is invalid.
InvalidEnableMBFlag = 60014,
/// This contract instance cannot be initialized again.
AlreadyInitialized = 60015,
/// The mint and burn mode is disabled.
MintBurnDisabled = 60016,
CannotTargetSelfUser = 60017,
InvalidBurnTarget = 60018,
MissingPackageHashForUpgrade = 60019,
}
impl From<AvailabilityError> for ApiError {
fn from(error: AvailabilityError) -> Self {
ApiError::User(error as u16)
}
}

View File

@ -1,101 +0,0 @@
#![no_std]
#![no_main]
extern crate alloc;
pub mod constants;
pub mod entry_points;
mod error;
use alloc::{
collections::BTreeMap,
format,
string::{String, ToString},
vec,
vec::Vec,
};
//use casper_contract::contract_api::{self};
use casper_contract::{
contract_api::{
runtime::{self, get_caller, get_key, get_named_arg, put_key, revert},
storage::{self, dictionary_put},
},
unwrap_or_revert::UnwrapOrRevert,
};
use casper_types::{
api_error::ApiError, bytesrepr::ToBytes, contracts::NamedKeys, runtime_args, CLValue,
ContractHash, ContractPackageHash, Key, RuntimeArgs, URef, U256,
};
use entry_points::generate_entry_points;
const CONTRACT_PACKAGE_NAME: &str = "package_name";
const CONTRACT_ACCESS_UREF: &str = "access_uref";
const CONTRACT_VERSION_KEY: &str = "version";
const CONTRACT_KEY: &str = "availability";
const MESSAGE_KEY: &str = "message";
#[no_mangle]
pub extern "C" fn hello() {
let message: String = runtime::get_named_arg("message");
let uref: URef = runtime::get_key(MESSAGE_KEY)
.unwrap_or_revert_with(ApiError::MissingKey)
.into_uref()
.unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);
storage::write(uref, message);
}
#[no_mangle]
pub extern "C" fn query() {
let uref: URef = runtime::get_key(MESSAGE_KEY)
.unwrap_or_revert_with(ApiError::MissingKey)
.into_uref()
.unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);
let result: String = storage::read(uref)
.unwrap_or_revert_with(ApiError::Read)
.unwrap_or_revert_with(ApiError::ValueNotFound);
let typed_result = CLValue::from_t(result).unwrap_or_revert();
runtime::ret(typed_result); // Return the message value.
}
#[no_mangle]
pub extern "C" fn stake_availability() {}
#[no_mangle]
pub extern "C" fn assign_work() {}
#[no_mangle]
pub extern "C" fn get_assigned_work() {}
// Entry point that executes automatically when a caller installs the contract.
#[no_mangle]
pub extern "C" fn call() {
let message = storage::new_uref("initial message");
// In the named keys of the contract, add a key for the message
let mut named_keys = NamedKeys::new();
let key_name = String::from(MESSAGE_KEY);
named_keys.insert(key_name, message.into());
// Create the entry points for this contract.
let entry_points = generate_entry_points();
// Create a new contract package that can be upgraded.
let (stored_contract_hash, contract_version) = storage::new_contract(
entry_points,
Some(named_keys),
Some(CONTRACT_PACKAGE_NAME.to_string()),
Some(CONTRACT_ACCESS_UREF.to_string()),
);
/* To create a locked contract instead, use new_locked_contract and throw away the contract version returned.
let (stored_contract_hash, _) =
storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None); */
// Store the contract version in the context's named keys.
let version_uref = storage::new_uref(contract_version);
runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());
// Create a named key for the contract hash.
runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());
}

View File

@ -1 +0,0 @@
nightly-2023-01-09

View File

@ -1,18 +0,0 @@
[package]
name = "validation-pool"
version = "0.1.0"
edition = "2021"
description = "Contract for minting and distributing reputation through consensus"
[dependencies]
casper-contract = "4.0.0"
casper-types = "4.0.1"
[[bin]]
name = "validation_pool"
path = "src/main.rs"
bench = false
doctest = false
test = false

View File

@ -1,4 +0,0 @@
// Entry points
// Entry point: Initiate Validation Pool
// Entry point: Stake REP in Validation Pool
// Entry point: Evaluate outcome of Validation Pool

View File

@ -1,20 +0,0 @@
#![no_std]
#![no_main]
pub mod entry_points;
#[no_mangle]
pub extern "C" fn initiate_validation_pool() {}
#[no_mangle]
pub extern "C" fn stake() {}
#[no_mangle]
pub extern "C" fn evaluate_outcome() {}
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

View File

@ -1,16 +0,0 @@
[package]
name = "work-1"
version = "0.1.0"
edition = "2021"
description = "Contract for interfacing with the public to provide a fee-based service"
[dependencies]
casper-contract = "4.0.0"
casper-types = "4.0.1"
[[bin]]
name = "work_1"
path = "src/main.rs"
bench = false
doctest = false
test = false

View File

@ -1 +0,0 @@
stable

View File

@ -1,4 +0,0 @@
// Entry points
// Entry point: Customer sends CSPR to request work
// Entry point: Worker submits work evidence
// Entry point: Customer submits satisfied/unsatisfied

View File

@ -1,20 +0,0 @@
#![no_std]
#![no_main]
pub mod entry_points;
#[no_mangle]
pub extern "C" fn request_work() {}
#[no_mangle]
pub extern "C" fn submit_work_evidence() {}
#[no_mangle]
pub extern "C" fn submit_customer_satisfaction() {}
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

View File

@ -16,10 +16,11 @@ module.exports = {
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: ['test/**'],
devDependencies: ['test/**', 'scripts/**'],
optionalDependencies: false,
peerDependencies: false,
},
],
'no-console': 0,
},
};

View File

@ -1,28 +1,16 @@
// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat
// will compile your contracts, add the Hardhat Runtime Environment's members to the
// global scope, and execute the script.
const hre = require("hardhat");
const { ethers } = require('hardhat');
async function main() {
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
const unlockTime = currentTimestampInSeconds + 60;
const dao = await ethers.deployContract('DAO');
await dao.waitForDeployment();
const lockedAmount = hre.ethers.parseEther("0.001");
console.log(`DAO deployed to ${dao.target}`);
const lock = await hre.ethers.deployContract("Lock", [unlockTime], {
value: lockedAmount,
});
const WORK1_PRICE = ethers.parseEther('0.001');
const work1 = await ethers.deployContract('Work1', [dao.target, WORK1_PRICE]);
await work1.waitForDeployment();
await lock.waitForDeployment();
console.log(
`Lock with ${ethers.formatEther(
lockedAmount
)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}`
);
console.log(`Work1 deployed to ${work1.target}`);
}
// We recommend this pattern to be able to use async/await everywhere

View File

@ -1,59 +0,0 @@
const {
time,
loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
const { expect } = require("chai");
describe("Lock", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployOneYearLockFixture() {
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const ONE_GWEI = 1_000_000_000;
const lockedAmount = ONE_GWEI;
const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();
const Lock = await ethers.getContractFactory("Lock");
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
return { lock, unlockTime, lockedAmount, owner, otherAccount };
}
describe("Deployment", function () {
it("Should set the right unlockTime", async function () {
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
expect(await lock.unlockTime()).to.equal(unlockTime);
});
it("Should set the right owner", async function () {
const { lock, owner } = await loadFixture(deployOneYearLockFixture);
expect(await lock.owner()).to.equal(owner.address);
});
it("Should receive and store the funds to lock", async function () {
const { lock, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
expect(await ethers.provider.getBalance(lock.target)).to.equal(
lockedAmount
);
});
it("Should fail if the unlockTime is not in the future", async function () {
// We don't use the fixture here because we want a different deployment
const latestTime = await time.latest();
const Lock = await ethers.getContractFactory("Lock");
await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
"Unlock time should be in the future"
);
});
});
});