Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

Dojang is a service that issues offchain information (outside the blockchain) as onchain attestations on the GIWA chain. It plays an important role in linking onchain wallet addresses with offchain information. This allows users to hold an onchain identity without revealing Personally Identifiable Information (PII) from their wallet.

Dojang aims to establish the trust layer of the Giwa ecosystem by leveraging Ethereum Attestation Service (EAS).
Dojang aims to establish the trust layer of the GIWA ecosystem by leveraging Ethereum Attestation Service (EAS).

## Contracts

### Giwa Testnet (Sepolia)
### GIWA Testnet (Sepolia)

- Schemas

Expand All @@ -16,7 +16,7 @@ Dojang aims to establish the trust layer of the Giwa ecosystem by leveraging Eth
| Verified Address | Wallet address which is verified by a trusted issuer | `bool isVerified` | `0x568eb581cdf80b03d3bdfa414f3203bfdcc4bba4e66355612bd0e879da812f06` | `0x072d75e18b2be4f89a13a7147240477481c4b526d5795802acba59046b426e08` |
| Balance Root | Root of a Merkle tree of balances | `uint256 coinType,uint64 snapshotAt,uint192 leafCount,uint256 totalAmount,bytes32 root` | `0xf09c1384d860519bb4ea5bb2a45ab64b00a8d900d47fb79203663be6da21e06c` | `0x369faa9c2cd261c45be3db5e230b585f5f1abecf8e12be575bb543e917e6db52` |
| Verified Balance | User's balance verified by a trusted issuer | `uint256 balance,bytes32 salt,bytes32[] proofs` | `0x06c3bd846f5ea60b0b6f5a835ef85fd8253b53f67917d6c690be628d032f841b` | `0x77bf88ca262cc63e1b185dccd870aacc5320b8987ef6c7169920f265fe6ab5e9` |

| Verified Code | Authentication code verified by a trusted issuer | `bytes32 codeHash,string domain` | `0x68053e055c01ce9b3577f3162b36324bb195ebcb574c48e823480d205f06af9b` | `0x55ac1369dac97522d062b89ffdc4e752b48fbeba86915fdb956c7c2d0501d280` |

- Contracts

Expand All @@ -30,7 +30,8 @@ Dojang aims to establish the trust layer of the Giwa ecosystem by leveraging Eth
| AddressDojangResolver | Triggered on issuance or revocation of a Verified Address attestation | [`0x692009FE206C3F897867F6BF7B5B45506B747F9e`](https://sepolia-explorer.giwa.io/address/0x692009FE206C3F897867F6BF7B5B45506B747F9e) | v0.2.0 |
| BalanceRootDojangResolver | Triggered on issuance or revocation of a Balance Root attestation | [`0xD90a964aB65bc02397De1E7fcBd230803bC1bEd0`](https://sepolia-explorer.giwa.io/address/0xD90a964aB65bc02397De1E7fcBd230803bC1bEd0) | v0.4.0 |
| BalanceDojangResolver | Triggered on issuance or revocation of a Verified Balance attestation | [`0x6FFa7ABc1E380Bb967C78D5E648EF804e1fE6dAd`](https://sepolia-explorer.giwa.io/address/0x6FFa7ABc1E380Bb967C78D5E648EF804e1fE6dAd) | v0.4.0 |
| DojangScroll | Provides convenient read access to Dojang data | [`0xd5077b67dcb56caC8b270C7788FC3E6ee03F17B9`](https://sepolia-explorer.giwa.io/address/0xd5077b67dcb56caC8b270C7788FC3E6ee03F17B9) | v0.4.0 |
| VerifyCodeDojangResolver | Triggered on issuance or revocation of a Verified Code attestation | [`0x843fF433f7657901118fF3E2Eca915abb9BC12Df`](https://sepolia-explorer.giwa.io/address/0x843fF433f7657901118fF3E2Eca915abb9BC12Df) | v0.5.0 |
| DojangScroll | Provides convenient read access to Dojang data | [`0xd5077b67dcb56caC8b270C7788FC3E6ee03F17B9`](https://sepolia-explorer.giwa.io/address/0xd5077b67dcb56caC8b270C7788FC3E6ee03F17B9) | v0.5.0 |


## Usage
Expand Down
397 changes: 397 additions & 0 deletions broadcast/03-DeployVerifyCodeDojang.s.sol/91342/run-1764576757886.json

Large diffs are not rendered by default.

397 changes: 397 additions & 0 deletions broadcast/03-DeployVerifyCodeDojang.s.sol/91342/run-latest.json

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions broadcast/Upgrade.s.sol/91342/run-1764577197151.json

Large diffs are not rendered by default.

199 changes: 42 additions & 157 deletions broadcast/Upgrade.s.sol/91342/run-latest.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion deploy-config/91342.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"DojangAttesterBook": "0xDA282E89244424E297Ce8e78089B54D043FB28B6",
"DojangScroll": "0xd5077b67dcb56caC8b270C7788FC3E6ee03F17B9",
"SchemaBook": "0x78cBb3413FBb6aF05EF1D21e646440e56baE3AD6",
"BalanceRootDojangResolver": "0xD90a964aB65bc02397De1E7fcBd230803bC1bEd0"
"BalanceRootDojangResolver": "0xD90a964aB65bc02397De1E7fcBd230803bC1bEd0",
"VerifyCodeDojangResolver": "0x843fF433f7657901118fF3E2Eca915abb9BC12Df"
}
3 changes: 2 additions & 1 deletion deployments/91342-deploy.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"DojangAttesterBook": "0xDA282E89244424E297Ce8e78089B54D043FB28B6",
"DojangScroll": "0xd5077b67dcb56caC8b270C7788FC3E6ee03F17B9",
"SchemaBook": "0x78cBb3413FBb6aF05EF1D21e646440e56baE3AD6",
"BalanceRootDojangResolver": "0xD90a964aB65bc02397De1E7fcBd230803bC1bEd0"
"BalanceRootDojangResolver": "0xD90a964aB65bc02397De1E7fcBd230803bC1bEd0",
"VerifyCodeDojangResolver": "0x843fF433f7657901118fF3E2Eca915abb9BC12Df"
}
4 changes: 4 additions & 0 deletions offchain-specs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Dojang Off-chain Specs

This directory contains **reference implementations** and **formal specs**
for off-chain logic that must be consistent across all issuers and verifiers.
41 changes: 41 additions & 0 deletions offchain-specs/verify-code/VerifyCodeSpec.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @notice Off-chain reference implementation for VerifyCode Dojang.
/// @dev This contract is NEVER deployed on-chain. It exists solely as a spec.
library VerifyCodeSpec {
/// @notice Computes the codeHash from a user-facing code string.
/// @dev Rule: codeHash = keccak256(bytes(code))
function computeCodeHash(string memory code) internal pure returns (bytes32) {
return keccak256(bytes(code));
}

/// @notice Canonicalizes a domain string for VerifyCode usage.
/// @dev Rule: trim leading/trailing spaces, remove all internal spaces (0x20),
/// and lowercase ASCII characters only. Non-ASCII (e.g., Korean) characters are preserved as-is.
function canonicalizeDomain(string memory domain) internal pure returns (string memory) {
bytes memory b = bytes(domain);
uint256 start = 0;
uint256 end = b.length;

// trim leading/trailing spaces (0x20)
while (start < end && b[start] == 0x20) start++;
while (end > start && b[end - 1] == 0x20) end--;

// build canonicalized output: remove all spaces and lowercase ASCII
bytes memory out = new bytes(end - start);
uint256 n = 0;
for (uint256 i = start; i < end; i++) {
bytes1 c = b[i];
// skip any whitespace (0x20)
if (c == 0x20) continue;
// lowercase ASCII only
if (c >= 0x41 && c <= 0x5A) {
c = bytes1(uint8(c) + 32);
}
out[n++] = c;
}
assembly { mstore(out, n) }
return string(out);
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dojang",
"version": "0.4.0",
"version": "0.5.0",
"description": "Contracts for Dojang Service",
"engines": {
"node": ">=22.0.0"
Expand Down
22 changes: 21 additions & 1 deletion script/deploy/01-Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {AddressDojangResolver} from "src/AddressDojangResolver.sol";
import {DojangScroll} from "src/DojangScroll.sol";
import {BalanceDojangResolver} from "../../src/BalanceDojangResolver.sol";
import {BalanceRootDojangResolver} from "../../src/BalanceRootDojangResolver.sol";
import {VerifyCodeDojangResolver} from "../../src/VerifyCodeDojangResolver.sol";

contract Deploy is Script, Artifacts {
uint256 internal deployerKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
Expand All @@ -32,6 +33,7 @@ contract Deploy is Script, Artifacts {
string internal constant BALANCE_ROOT_DOJANG_SCHEMA =
"uint256 coinType,uint64 snapshotAt,uint192 leafCount,uint256 totalAmount,bytes32 root";
string internal constant BALANCE_DOJANG_SCHEMA = "uint256 balance,bytes32 salt,bytes32[] proofs";
string internal constant VERIFY_CODE_DOJANG_SCHEMA = "bytes32 codeHash,string domain";

ISchemaRegistry internal schemaRegistry = ISchemaRegistry(Predeploys.SCHEMA_REGISTRY);
IEAS internal eas = IEAS(Predeploys.EAS);
Expand Down Expand Up @@ -96,6 +98,13 @@ contract Deploy is Script, Artifacts {
save("BalanceRootDojangResolver", proxy);
}

function deployVerifyCodeDojangResolver() public broadcast(deployerKey) {
address proxy = Upgrades.deployUUPSProxy(
"VerifyCodeDojangResolver.sol", abi.encodeCall(VerifyCodeDojangResolver.initialize, admin)
);
save("VerifyCodeDojangResolver", proxy);
}

function deployBalanceDojangResolver() public broadcast(deployerKey) {
address proxy = Upgrades.deployUUPSProxy(
"BalanceDojangResolver.sol", abi.encodeCall(BalanceDojangResolver.initialize, admin)
Expand Down Expand Up @@ -145,6 +154,12 @@ contract Deploy is Script, Artifacts {
balanceRootDojangResolver.grantRole(balanceRootDojangResolver.UPGRADER_ROLE(), upgrader);
}

function grantRoleVerifyCodeDojangResolver() public broadcast(adminKey) {
VerifyCodeDojangResolver verifyCodeDojangResolver =
VerifyCodeDojangResolver(mustGetAddress("VerifyCodeDojangResolver"));
verifyCodeDojangResolver.grantRole(verifyCodeDojangResolver.UPGRADER_ROLE(), upgrader);
}

function grantRoleDojangScroll() public broadcast(adminKey) {
DojangScroll dojangScroll = DojangScroll(mustGetAddress("DojangScroll"));
dojangScroll.grantRole(dojangScroll.UPGRADER_ROLE(), upgrader);
Expand All @@ -158,11 +173,14 @@ contract Deploy is Script, Artifacts {
BalanceDojangResolver balanceDojangResolver = BalanceDojangResolver(mustGetAddress("BalanceDojangResolver"));
BalanceRootDojangResolver balanceRootDojangResolver =
BalanceRootDojangResolver(mustGetAddress("BalanceRootDojangResolver"));
VerifyCodeDojangResolver verifyCodeDojangResolver =
VerifyCodeDojangResolver(mustGetAddress("VerifyCodeDojangResolver"));
DojangScroll dojangScroll = DojangScroll(mustGetAddress("DojangScroll"));

addressDojangResolver.setIndexer(address(attestationIndexer));
balanceDojangResolver.setIndexer(address(attestationIndexer));
balanceRootDojangResolver.setIndexer(address(attestationIndexer));
verifyCodeDojangResolver.setIndexer(address(attestationIndexer));

dojangScroll.setSchemaBook(address(schemaBook));
dojangScroll.setDojangAttesterBook(address(dojangAttesterBook));
Expand All @@ -177,7 +195,9 @@ contract Deploy is Script, Artifacts {
bytes32 balanceRootSchemaUid =
schemaRegistry.register(BALANCE_ROOT_DOJANG_SCHEMA, balanceRootDojangResolver, true);
schemaBook.register(DojangSchemaIds.BALANCE_ROOT_DOJANG, balanceRootSchemaUid);

balanceDojangResolver.setBalanceRootSchemaUID(balanceRootSchemaUid);

bytes32 verifyCodeSchemaUid = schemaRegistry.register(VERIFY_CODE_DOJANG_SCHEMA, verifyCodeDojangResolver, true);
schemaBook.register(DojangSchemaIds.VERIFY_CODE_DOJANG, verifyCodeSchemaUid);
}
}
74 changes: 74 additions & 0 deletions script/deploy/03-DeployVerifyCodeDojang.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Script} from "forge-std/Script.sol";
import {Artifacts} from "../utils/Artifacts.s.sol";
import {DeployConfig} from "../utils/DeployConfig.s.sol";
import {ISchemaRegistry} from "../../dependencies/@eas-contracts-1.4.0/contracts/ISchemaRegistry.sol";
import {IEAS} from "@eas-contracts/contracts/IEAS.sol";
import {Predeploys, DojangSchemaIds} from "../../src/libraries/Types.sol";
import {VerifyCodeDojangResolver} from "../../src/VerifyCodeDojangResolver.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/src/Upgrades.sol";
import {SchemaBook} from "../../src/SchemaBook.sol";
import {AttestationIndexer} from "../../src/AttestationIndexer.sol";

contract DeployVerifyCodeDojang is Script, Artifacts, DeployConfig {
uint256 internal deployerKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
address internal deployer = vm.addr(deployerKey);

uint256 internal adminKey = vm.envUint("ADMIN_PRIVATE_KEY");
address internal admin = vm.addr(adminKey);

uint256 internal upgraderKey = vm.envUint("UPGRADER_PRIVATE_KEY");
address internal upgrader = vm.addr(upgraderKey);

uint256 internal pauserKey = vm.envUint("PAUSER_PRIVATE_KEY");
address internal pauser = vm.addr(pauserKey);

string internal constant VERIFY_CODE_DOJANG_SCHEMA = "bytes32 codeHash,string domain";

ISchemaRegistry internal schemaRegistry = ISchemaRegistry(Predeploys.SCHEMA_REGISTRY);
IEAS internal eas = IEAS(Predeploys.EAS);

modifier broadcast(uint256 privateKey) {
vm.startBroadcast(privateKey);
_;
vm.stopBroadcast();
}

function setUp() public override(Artifacts, DeployConfig) {
Artifacts.setUp();
DeployConfig.setUp();
}

function run() public {
deployVerifyCodeDojangResolver();
grantRoleVerifyCodeDojangResolver();
configure();
}

function deployVerifyCodeDojangResolver() public broadcast(deployerKey) {
address proxy = Upgrades.deployUUPSProxy(
"VerifyCodeDojangResolver.sol", abi.encodeCall(VerifyCodeDojangResolver.initialize, admin)
);
save("VerifyCodeDojangResolver", proxy);
}

function grantRoleVerifyCodeDojangResolver() public broadcast(adminKey) {
VerifyCodeDojangResolver verifyCodeDojangResolver =
VerifyCodeDojangResolver(mustGetAddress("VerifyCodeDojangResolver"));
verifyCodeDojangResolver.grantRole(verifyCodeDojangResolver.UPGRADER_ROLE(), upgrader);
}

function configure() public broadcast(adminKey) {
SchemaBook schemaBook = SchemaBook(getAddress(".SchemaBook"));
AttestationIndexer attestationIndexer = AttestationIndexer(getAddress(".AttestationIndexer"));
VerifyCodeDojangResolver verifyCodeDojangResolver =
VerifyCodeDojangResolver(mustGetAddress("VerifyCodeDojangResolver"));

verifyCodeDojangResolver.setIndexer(address(attestationIndexer));

bytes32 verifyCodeSchemaUid = schemaRegistry.register(VERIFY_CODE_DOJANG_SCHEMA, verifyCodeDojangResolver, true);
schemaBook.register(DojangSchemaIds.VERIFY_CODE_DOJANG, verifyCodeSchemaUid);
}
}
11 changes: 6 additions & 5 deletions script/upgrade/Upgrade.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ contract Upgrade is Script, DeployConfig {
upgradeUUPSContract(
getAddress(".BalanceDojangResolver"), "BalanceDojangResolver.sol", new bytes(0), new bytes(0)
);
if (keyExists(".BalanceRootDojangResolver")) {
upgradeUUPSContract(
getAddress(".BalanceRootDojangResolver"), "BalanceRootDojangResolver.sol", new bytes(0), new bytes(0)
);
}
upgradeUUPSContract(
getAddress(".BalanceRootDojangResolver"), "BalanceRootDojangResolver.sol", new bytes(0), new bytes(0)
);
upgradeUUPSContract(
getAddress(".VerifyCodeDojangResolver"), "VerifyCodeDojangResolver.sol", new bytes(0), new bytes(0)
);

upgradeUUPSContract(getAddress(".DojangScroll"), "DojangScroll.sol", new bytes(0), new bytes(0));
}
Expand Down
61 changes: 59 additions & 2 deletions src/DojangScroll.sol
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,38 @@ contract DojangScroll is UUPSUpgradeable, AccessControlUpgradeable, IDojangScrol
return attestation.uid;
}

/**
* @inheritdoc IDojangScroll
*/
function isVerifiedCode(
bytes32 codeHash,
string calldata domain,
DojangAttesterId attesterId
)
external
view
returns (bool)
{
return _getVerifyCodeAttestation(codeHash, domain, attesterId).isVerified();
}

/**
* @inheritdoc IDojangScroll
*/
function getVerifyCodeAttestationUid(
bytes32 codeHash,
string calldata domain,
DojangAttesterId attesterId
)
external
view
returns (bytes32)
{
Attestation memory attestation = _getVerifyCodeAttestation(codeHash, domain, attesterId);
attestation.verify();
return attestation.uid;
}

/**
* @dev Initializes the contract
* @param admin The address to be granted with the default admin Role
Expand All @@ -198,9 +230,9 @@ contract DojangScroll is UUPSUpgradeable, AccessControlUpgradeable, IDojangScrol
}

/// @notice Semantic version.
/// @custom:semver 0.4.0
/// @custom:semver 0.5.0
function version() public pure virtual returns (string memory) {
return "0.4.0";
return "0.5.0";
}

/**
Expand Down Expand Up @@ -284,4 +316,29 @@ contract DojangScroll is UUPSUpgradeable, AccessControlUpgradeable, IDojangScrol
bytes32 attestationUid = _indexer.getAttestationUid(easSchemaUid, attesterAddress, recipient, key);
return _EAS.getAttestation(attestationUid);
}

/**
* @notice Returns the verify-code attestation for the given codeHash and domain.
* @dev This function does not verify the existence or validity of the attestation.
* @param codeHash The hashed verification code
* @param domain The domain string associated with the verification code; should be canonicalized
* @param attesterId The attester identifier
* @return The verify-code attestation
*/
function _getVerifyCodeAttestation(
bytes32 codeHash,
string memory domain,
DojangAttesterId attesterId
)
internal
view
returns (Attestation memory)
{
bytes32 easSchemaUid = _schemaBook.getSchemaUid(DojangSchemaIds.VERIFY_CODE_DOJANG);
address attesterAddress = _dojangAttesterBook.getAttester(attesterId);

bytes32 key = keccak256(abi.encode(codeHash, domain));
bytes32 attestationUid = _indexer.getAttestationUid(easSchemaUid, attesterAddress, address(0), key);
return _EAS.getAttestation(attestationUid);
}
}
Loading