Skip to content

Commit

Permalink
chore: update TNT Core examples and bytecode (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
shekohex authored Jan 28, 2025
1 parent 27fe87e commit ac376f7
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 168 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/foundry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
version: v0.3.0

- name: Install Solidity Dependencies
run: forge soldeer update -d
Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
version: v0.3.0

- name: Install Solidity Dependencies
run: forge soldeer update -d
Expand Down
2 changes: 1 addition & 1 deletion bytecode/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tnt-core-bytecode"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
description = "Bytecode exports for TNT Core Solidity contracts"
license = "MIT"
Expand Down
3 changes: 2 additions & 1 deletion bytecode/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ fn main() {

let mut rust_code = String::from(
r#"//! TNT Core contract bytecode exports
//!
//!
//! This crate exports the bytecode of TNT Core contracts as constant byte vectors
//! that can be easily imported and used in other Rust projects.
/// Module containing all contract bytecodes
#[rustfmt::skip]
pub mod bytecode {
"#,
);
Expand Down
5 changes: 3 additions & 2 deletions bytecode/src/lib.rs

Large diffs are not rendered by default.

127 changes: 48 additions & 79 deletions examples/IncredibleSquaringBlueprint.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
pragma solidity ^0.8.20;

import "../src/BlueprintServiceManagerBase.sol";

Expand All @@ -14,7 +14,7 @@ contract IncredibleSquaringBlueprint is BlueprintServiceManagerBase {
* @dev A mapping of all service operators registered with the blueprint.
* The key is the operator's address and the value is the operator's details.
*/
mapping(address => bytes) public operators;
mapping(address => ServiceOperators.OperatorPreferences) public operators;

/**
* @dev A mapping of all service instances requested from the blueprint.
Expand All @@ -26,144 +26,113 @@ contract IncredibleSquaringBlueprint is BlueprintServiceManagerBase {
* @dev Hook for service operator registration. Called when a service operator
* attempts to register with the blueprint.
* @param operator The operator's details.
* @param _registrationInputs Inputs required for registration.
* @param registrationInputs Inputs required for registration.
*/
function onRegister(
bytes calldata operator,
bytes calldata _registrationInputs
) public payable override onlyFromRootChain {
ServiceOperators.OperatorPreferences calldata operator,
bytes calldata registrationInputs
)
public
payable
override
onlyFromMaster
{
// compute the operator's address from the operator's public key
address operatorAddress = operatorAddressFromPublicKey(operator);
address operatorAddress = ServiceOperators.asOperatorAddress(operator.ecdsaPublicKey);
// store the operator's details
operators[operatorAddress] = operator;
}

/**
* @dev Hook for service instance requests. Called when a user requests a service
* instance from the blueprint.
* @param serviceId The ID of the requested service.
* @param operators The operators involved in the service.
* @param _requestInputs Inputs required for the service request.
* @param params The parameters for the service request.
*/
function onRequest(
uint64 serviceId,
bytes[] calldata operators,
bytes calldata _requestInputs
) public payable override onlyFromRootChain {
function onRequest(ServiceOperators.RequestParams calldata params) public payable override onlyFromMaster {
// store the service instance request
for (uint i = 0; i < operators.length; i++) {
address operatorAddress = operatorAddressFromPublicKey(
operators[i]
);
serviceInstances[serviceId].push(operatorAddress);
for (uint256 i = 0; i < params.operators.length; i++) {
address operatorAddress = ServiceOperators.asOperatorAddress(params.operators[i].ecdsaPublicKey);
serviceInstances[params.requestId].push(operatorAddress);
}
}

/**
* @dev Hook for job calls on the service. Called when a job is called within
* the service context.
* @param serviceId The ID of the service where the job is called.
* @param job The job identifier.
* @param jobCallId A unique ID for the job call.
* @param inputs Inputs required for the job execution in bytes format.
*/
function onJobCall(
uint64 serviceId,
uint8 job,
uint64 jobCallId,
bytes calldata inputs
) public payable override onlyFromRootChain {
)
public
payable
override
onlyFromMaster
{
// Implement job call logic here
}

/**
* @dev Hook for handling job result. Called when operators send the result
* of a job execution.
* @param serviceId The ID of the service related to the job.
* @param job The job identifier.
* @param jobCallId The unique ID for the job call.
* @param operator The operator (operator) sending the result in bytes format.
* @param inputs Inputs used for the job execution in bytes format.
* @param outputs Outputs resulting from the job execution in bytes format.
*/
function onJobResult(
uint64 serviceId,
uint8 job,
uint64 jobCallId,
bytes calldata operator,
ServiceOperators.OperatorPreferences calldata operator,
bytes calldata inputs,
bytes calldata outputs
) public payable virtual override onlyFromRootChain {
)
public
payable
override
onlyFromMaster
{
// Do something with the job result
}

/**
* @dev Verifies the result of a job call. This function is used to validate the
* outputs of a job execution against the expected results.
* @param serviceId The ID of the service related to the job.
* @param job The job identifier.
* @param jobCallId The unique ID for the job call.
* @param operator The operator (operator) whose result is being verified.
* @param inputs Inputs used for the job execution.
* @param outputs Outputs resulting from the job execution.
* @return bool Returns true if the job call result is verified successfully,
* otherwise false.
* @dev Verifies the result of a job call.
*/
function verifyResult(
uint64 serviceId,
uint8 job,
uint64 jobCallId,
bytes calldata operator,
ServiceOperators.OperatorPreferences calldata operator,
bytes calldata inputs,
bytes calldata outputs
) public view returns (bool) {
// Someone requested to verify the result of a job call.
// We need to check if the output is the square of the input.

)
public
view
returns (bool)
{
// check if job is zero.
require(job == 0, "Job not found");
// Check if the operator is a registered operator, so we can slash
// their stake if they are cheating.
address operatorAddress = operatorAddressFromPublicKey(operator);
require(
operators[operatorAddress].length > 0,
"Operator not registered"
);

// Check if the operator is a registered operator
address operatorAddress = ServiceOperators.asOperatorAddress(operator.ecdsaPublicKey);
require(operators[operatorAddress].ecdsaPublicKey.length > 0, "Operator not registered");

// Check if operator is part of the service instance
require(
isOperatorInServiceInstance(serviceId, operatorAddress),
"Operator not part of service instance"
);
require(isOperatorInServiceInstance(serviceId, operatorAddress), "Operator not part of service instance");

// Decode the inputs and outputs
uint256 input = abi.decode(inputs, (uint256));
uint256 output = abi.decode(outputs, (uint256));
// Check if the output is the square of the input
bool isValid = output == input * input;
if (!isValid) {
// Slash the operator's stake if the result is invalid
// Using ServicesPrecompile to slash the operator's stake
// slashPercent = 10; // 10% slash
// ServicesPrecompile.slash(serviceId, operator, slashPercent);
}

return isValid;
// Check if the output is the square of the input
return output == input * input;
}

function isOperatorInServiceInstance(
uint64 serviceId,
address operatorAddress
) public view returns (bool) {
for (uint i = 0; i < serviceInstances[serviceId].length; i++) {
function isOperatorInServiceInstance(uint64 serviceId, address operatorAddress) public view returns (bool) {
for (uint256 i = 0; i < serviceInstances[serviceId].length; i++) {
if (serviceInstances[serviceId][i] == operatorAddress) {
return true;
}
}
return false;
}

function operatorAddressFromPublicKey(
bytes calldata publicKey
) public pure returns (address) {
return address(uint160(uint256(keccak256(publicKey))));
}
}
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 14 additions & 35 deletions test/AssetsLib.t.sol
Original file line number Diff line number Diff line change
@@ -1,33 +1,28 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

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

contract AssetsLibTest is Test {
// Test constants
address constant TEST_ERC20_ADDRESS = address(0x1234567890123456789012345678901234567890);
bytes32 constant TEST_ASSET_ID = bytes32(uint256(123));

function setUp() public {
// No setup required as we're testing a library
}

function testErc20AssetConversion() public {
Assets.Asset memory asset = Assets.Asset({
kind: Assets.Kind.Erc20,
data: bytes32(uint256(uint160(TEST_ERC20_ADDRESS)))
});
Assets.Asset memory asset =
Assets.Asset({ kind: Assets.Kind.Erc20, data: bytes32(uint256(uint160(TEST_ERC20_ADDRESS))) });

address result = Assets.toAddress(asset);
assertEq(result, TEST_ERC20_ADDRESS, "ERC20 address conversion failed");
}

function testCustomAssetConversion() public {
Assets.Asset memory asset = Assets.Asset({
kind: Assets.Kind.Custom,
data: TEST_ASSET_ID
});
Assets.Asset memory asset = Assets.Asset({ kind: Assets.Kind.Custom, data: TEST_ASSET_ID });

address result = Assets.toAddress(asset);
assertTrue(Assets.isAssetIdCompatible(result), "Custom asset address should be compatible");
Expand All @@ -47,15 +42,10 @@ contract AssetsLibTest is Test {
}

function testAssetTypeChecks() public {
Assets.Asset memory erc20Asset = Assets.Asset({
kind: Assets.Kind.Erc20,
data: bytes32(uint256(uint160(TEST_ERC20_ADDRESS)))
});
Assets.Asset memory erc20Asset =
Assets.Asset({ kind: Assets.Kind.Erc20, data: bytes32(uint256(uint160(TEST_ERC20_ADDRESS))) });

Assets.Asset memory customAsset = Assets.Asset({
kind: Assets.Kind.Custom,
data: TEST_ASSET_ID
});
Assets.Asset memory customAsset = Assets.Asset({ kind: Assets.Kind.Custom, data: TEST_ASSET_ID });

assertTrue(Assets.isErc20(erc20Asset), "Should be identified as ERC20");
assertFalse(Assets.isErc20(customAsset), "Should not be identified as ERC20");
Expand All @@ -77,30 +67,19 @@ contract AssetsLibTest is Test {

function testNativeAssetChecks() public {
// Test native ERC20 (address(0))
Assets.Asset memory nativeErc20 = Assets.Asset({
kind: Assets.Kind.Erc20,
data: bytes32(0)
});
Assets.Asset memory nativeErc20 = Assets.Asset({ kind: Assets.Kind.Erc20, data: bytes32(0) });
assertTrue(Assets.isNative(nativeErc20), "Should identify native ERC20");

// Test native Custom asset (id = 0)
Assets.Asset memory nativeCustom = Assets.Asset({
kind: Assets.Kind.Custom,
data: bytes32(0)
});
Assets.Asset memory nativeCustom = Assets.Asset({ kind: Assets.Kind.Custom, data: bytes32(0) });
assertTrue(Assets.isNative(nativeCustom), "Should identify native Custom asset");

// Test non-native assets
Assets.Asset memory nonNativeErc20 = Assets.Asset({
kind: Assets.Kind.Erc20,
data: bytes32(uint256(uint160(TEST_ERC20_ADDRESS)))
});
Assets.Asset memory nonNativeErc20 =
Assets.Asset({ kind: Assets.Kind.Erc20, data: bytes32(uint256(uint160(TEST_ERC20_ADDRESS))) });
assertFalse(Assets.isNative(nonNativeErc20), "Should not identify as native ERC20");

Assets.Asset memory nonNativeCustom = Assets.Asset({
kind: Assets.Kind.Custom,
data: TEST_ASSET_ID
});
Assets.Asset memory nonNativeCustom = Assets.Asset({ kind: Assets.Kind.Custom, data: TEST_ASSET_ID });
assertFalse(Assets.isNative(nonNativeCustom), "Should not identify as native Custom asset");
}
}
Loading

0 comments on commit ac376f7

Please sign in to comment.