Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
76b2126
CyberCorp Extension Data first pass
merisman May 6, 2026
dd7809a
Fund Extension
merisman Jun 3, 2026
ab7b3e9
wip: feat: deal manager secondary trades
Detoo Jun 5, 2026
84c685d
wip: chore: minor refactoring
Detoo Jun 6, 2026
e82f873
test: add cases for threshold conditions
Detoo Jun 8, 2026
3840a16
CyberCertPrinter Size Reductions
merisman Jun 11, 2026
e263357
Added per cert hook mapping check back in.
merisman Jun 11, 2026
d750f56
wip: defer agreement creation to acceptOffer()
Detoo Jun 11, 2026
01e6fed
fix: bug fixes. Add notes on architectures
Detoo Jun 12, 2026
f0b7647
feat: cancelOffer with voidOutstandingSettlements. Misc fixes
Detoo Jun 12, 2026
73a3f48
fix: in-flight settlement should not be cancellable by cancelOffer().…
Detoo Jun 13, 2026
d527507
wip: fix: DealManager size
Detoo Jun 14, 2026
0882f73
Adding unitsReserved and timestamps
merisman Jun 14, 2026
25787d7
feat: fix DealManager size by converting LexScroWLite to a pure libra…
Detoo Jun 15, 2026
aa499b8
fix: address PR comments
Detoo Jun 15, 2026
efaec7e
feat: clean separation between primary and secondary trade functions …
Detoo Jun 17, 2026
e004b7f
new cybercertprinter tests
merisman Jun 17, 2026
1cdfba7
additional tests
merisman Jun 17, 2026
b9f8f8b
test: increase coverage on Settlement escrow state machine
Detoo Jun 17, 2026
0acb4b2
test: increase coverage on threshold & closing conditions
Detoo Jun 17, 2026
343c6ca
fix: missing implementation for Spec §12B.4 fall-through. Increase te…
Detoo Jun 18, 2026
a04c0fa
Restrictive Legend Update
merisman Jun 19, 2026
3a28f95
Update CyberCertPrinterStorage.sol
merisman Jun 19, 2026
f7536db
Updates to restrictive legends
merisman Jun 19, 2026
fb35aff
fix: update threshold conditions and integrator fee configs to spec
Detoo Jun 19, 2026
aff5502
fix: missing per-settlement fields. Add tests for indexer
Detoo Jun 22, 2026
325089f
Merge remote-tracking branch 'origin/develop' into feat/legion
Detoo Jun 23, 2026
f16f37c
test: fix broken tests. Minor refactoring
Detoo Jun 23, 2026
3c8586b
fix: disabled IssuanceManagerWithMigration due to contract size viola…
Detoo Jun 23, 2026
389c911
Merge remote-tracking branch 'origin/feat/legion' into feat/deal-mana…
Detoo Jun 23, 2026
0484de1
fix: update unit reservation API to spec
Detoo Jun 23, 2026
aa76074
feat: re-check threshold conditions at finalization
Detoo Jun 24, 2026
d84600b
Adding in unique holder counts for cybercerts/LETs
merisman Jun 24, 2026
cf67769
Merge remote-tracking branch 'origin/feat/legion' into feat/deal-mana…
Detoo Jun 24, 2026
e682d92
wip: feat: secondary transfer and open endorsement. Fix IssuanceManag…
Detoo Jun 24, 2026
7dc3918
feat: simplify secondary transfer and endorsement. Refactor tests to …
Detoo Jun 25, 2026
bead079
feat: secondary trading to support administered hosting mode. Increas…
Detoo Jun 26, 2026
811866d
feat: enforce min. threshold on remainder lots per requested
Detoo Jun 26, 2026
008b9d8
feat: add support indexes to CyberCertPrinter
Detoo Jun 26, 2026
623388b
fix: CyberCertPrinter legal owner indexes to be backward compatible a…
Detoo Jun 26, 2026
3e0bf1e
Merge pull request #111 from MetaLex-Tech/feat/cert-legal-owner-indexing
Detoo Jun 30, 2026
df39f98
Merge remote-tracking branch 'origin/feat/legion' into feat/deal-mana…
Detoo Jun 30, 2026
6012d04
feat: recert to share the same `_selectFirstLegalOwnedToken()` with s…
Detoo Jun 30, 2026
bf17943
fix: handle primary issuance-related cert details at secondary transfer
Detoo Jun 30, 2026
3355141
feat: enhance secondary transfer events for ease of token transfer le…
Detoo Jun 30, 2026
dd714ed
feat: optimize secondary transfer events and make it more consistent …
Detoo Jul 1, 2026
9d116c7
fix: scripifying cert should respect reserved units
Detoo Jul 1, 2026
cb9d389
fix: apply reserved-units check for certificate details update
Detoo Jul 1, 2026
1647751
Merge pull request #112 from MetaLex-Tech/fix/scripify-reserved-units
Detoo Jul 1, 2026
7cdbbd2
Merge remote-tracking branch 'origin/feat/legion' into feat/deal-mana…
Detoo Jul 1, 2026
0d362eb
fix: secondary transfer unit calculation interfered with scripified o…
Detoo Jul 1, 2026
2dc4e6b
feat: secondary trading to use strong-typing BaseSecondaryTradingCond…
Detoo Jul 2, 2026
a3392a2
feat: relayer support for post/accept/cancelOffer
Detoo Jul 2, 2026
c18fdbf
feat: relayer support for voiding offer
Detoo Jul 3, 2026
a8ee973
Merge pull request #109 from MetaLex-Tech/feat/deal-manager-secondary…
merisman Jul 3, 2026
2357be4
fix: audit: cert legal ownership
Detoo Jul 3, 2026
877534a
fix: audit: cert printer validation
Detoo Jul 3, 2026
9ab05cf
fix: audit: settlement expiry
Detoo Jul 3, 2026
a77dac3
fix: audit: secondary trade seller ownership checks
Detoo Jul 3, 2026
5f6ef21
Merge pull request #113 from MetaLex-Tech/fix/secondary-trading-inter…
merisman Jul 3, 2026
58455d6
fix: cert should not transfer legal ownership amid escrow
Detoo Jul 3, 2026
163f245
Initial Condition Dump
merisman Jul 3, 2026
d1f72ee
Merge remote-tracking branch 'origin/feat/legion' into feat/legion-co…
Detoo Jul 4, 2026
b5cc4d9
wip: test: add end-to-end cases for each exemption pathway (happy pat…
Detoo Jul 4, 2026
cdaa67b
chore: separate build size tests and unit tests
Detoo Jul 4, 2026
9880b12
Updates to conditions and pathways. Additional Tests
merisman Jul 6, 2026
7094f3a
Merge pull request #114 from MetaLex-Tech/feat/legion-conditions
merisman Jul 6, 2026
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
22 changes: 17 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ env:
FOUNDRY_PROFILE: ci

jobs:
unit:
name: Unit tests
size:
name: Build sizes
runs-on: ubuntu-latest
environment: test
steps:
Expand All @@ -30,6 +30,21 @@ jobs:
- name: Build
run: forge build --use solc:0.8.28 --via-ir --optimize --optimizer-runs 15 --sizes

unit:
name: Unit tests
runs-on: ubuntu-latest
environment: test
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Show Forge version
run: forge --version

- name: Unit tests
run: forge test --use solc:0.8.28 --via-ir --optimize --optimizer-runs 15 -vvv --nmc '(ForkTest|AdhocTest)'

Expand All @@ -48,9 +63,6 @@ jobs:
- name: Show Forge version
run: forge --version

- name: Build
run: forge build --use solc:0.8.28 --via-ir --optimize --optimizer-runs 15 --sizes

- name: Fork tests
env:
ALCHEMY_API_KEY: "${{ secrets.ALCHEMY_API_KEY }}"
Expand Down
193 changes: 97 additions & 96 deletions script/upgrade-legacy-issuance-managers.s.sol
Original file line number Diff line number Diff line change
@@ -1,99 +1,100 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import {Script} from "forge-std/Script.sol";
import {Test, console2} from "forge-std/Test.sol";
import {CyberCorpFactory} from "../src/CyberCorpFactory.sol";
import {CyberCertPrinter} from "../src/CyberCertPrinter.sol";
import {IIssuanceManager} from "../src/interfaces/IIssuanceManager.sol";
import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol";
import {BorgAuth} from "../src/libs/auth.sol";
import {CyberAgreementRegistry} from "../src/CyberAgreementRegistry.sol";
import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol";
import {IDealManager} from "../src/interfaces/IDealManager.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {CertificateDetails} from "../src/storage/CyberCertPrinterStorage.sol";
import "../src/CyberCorpConstants.sol";
import {CertificateUriBuilder} from "../src/CertificateUriBuilder.sol";
import {SAFTExtension} from "../src/storage/extensions/SAFTExtension.sol";
import {IssuanceManager} from "../src/IssuanceManager.sol";
import {IssuanceManagerWithMigration} from "../src/IssuanceManagerWithMigration.sol";
import {ILegacyFactory} from "./interfaces/ILegacyFactory.sol";
import {KnownAddressesLoader} from "./libs/KnownAddressesLoader.sol";
import {CyberCorp} from "../src/CyberCorp.sol";

contract UpgradeLegacyIssuanceManagersScript is Script {
function run() public returns (IssuanceManagerWithMigration) {
return runWithArgs(type(uint256).max);
}

function runWithArgs(uint256 maxCount) public returns (IssuanceManagerWithMigration) {
bytes32 salt = bytes32(keccak256("MetaLexCyberCorp.PublicRounds.UpgradeV3.0.2"));
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY_MAIN");

CyberCorpFactory cyberCorpFactory = CyberCorpFactory(0x51413048f3Dfc4516e95BC8e249341B1D53B6cB2);
IssuanceManagerFactory imFactoryV2 = IssuanceManagerFactory(cyberCorpFactory.issuanceManagerFactory()); // this is the v2 one (with reference implementation)

// CyberCertPrinter beacons are owned by each individual IssuanceManagers, so to upgrade them we must
// enumerate all existing IssuanceManager addresses and their corresponding factories (https://dune.com/queries/6129394):
// - 0xA32547aAdAA4975082D729c79e79dBaE4385EBCf
// - 0xade5d9fBaC6201535dc558FBD247e6859f5aa8C5 (deprecated, won't touch it)
ILegacyFactory legacyImFactory = ILegacyFactory(0xA32547aAdAA4975082D729c79e79dBaE4385EBCf);

// Load all known cyber corps
address[] memory knownCyberCorps = KnownAddressesLoader.load(block.chainid, "/script/res/known-cyber-corps.json", maxCount);

vm.startBroadcast(deployerPrivateKey);

//
// Upgrade legacy DealManagers
//

// Upgrade beacon implementation to the new implementation (with migration feature)

IssuanceManagerWithMigration imWithMigrationImpl = new IssuanceManagerWithMigration();

// Expect new factory to be deployed at a predetermined address because we will hard-code it to the migration contract
vm.assertEq(cyberCorpFactory.issuanceManagerFactory(), imWithMigrationImpl.NEW_UPGRADE_FACTORY(), "new issuanceManagerFactory address has changed, update it in IssuanceManagerWithMigration");

// Upgrade beacon to a special implementation with migration features
legacyImFactory.upgradeImplementation(address(imWithMigrationImpl));
vm.assertEq(legacyImFactory.getBeaconImplementation(), address(imWithMigrationImpl), "beacon implementation should be upgraded with migration features by now");
console2.log("Set new beacon implementation (with migration features): %s for legacy IssuanceManagerFactory: %s", address(imWithMigrationImpl), address(legacyImFactory));

// This is the ugly part: One-time manual upgrade required for legacy DealManagers.
// This section updates the `upgradeFactory` pointer to the new permanent factory address,
// enabling access to updated fee-related methods. This migration is performed one-by-one
// for each legacy IssuanceManager contract.

// This is a ONE-TIME operation per legacy IssuanceManager's lifetime. Once updated,
// the `upgradeFactory` is expected to remain permanent and unchanged for all following upgrades.
for (uint256 i = 0; i < knownCyberCorps.length; i++) {
address imAddr = CyberCorp(knownCyberCorps[i]).issuanceManager();
IssuanceManagerWithMigration(imAddr).migrateUpgradeFactory();
vm.assertNotEq(IssuanceManagerFactory(IssuanceManager(imAddr).getUpgradeFactory()).getRefImplementation(), address(0), "should be able to lookup reference implementation now");
vm.assertEq(
IssuanceManager(imAddr).getCertPrinterBeaconImplementation(),
IssuanceManagerFactory(cyberCorpFactory.issuanceManagerFactory()).getCyberCertPrinterRefImplementation(),
"should point CyberCertPrinter implementation to reference now"
);
vm.assertEq(
IssuanceManager(imAddr).getScripBeaconImplementation(),
IssuanceManagerFactory(cyberCorpFactory.issuanceManagerFactory()).getCyberScripRefImplementation(),
"should point CyberScrip implementation to reference now"
);
console2.log("Migrated legacy IssuanceManager: %s", imAddr);
}

// Upgrade beacon to the normal implementation since migration is done
address refImplementation = imFactoryV2.getRefImplementation();
legacyImFactory.upgradeImplementation(refImplementation);
vm.assertEq(legacyImFactory.getBeaconImplementation(), refImplementation, "beacon implementation should be upgraded without migration features by now");
console2.log("Set new beacon implementation (without migration features): %s for legacy IssuanceManagerFactory: %s", address(refImplementation), address(legacyImFactory));

vm.stopBroadcast();

return imWithMigrationImpl;
}
}
// TODO commented out for now due to contract size violation
//import {Script} from "forge-std/Script.sol";
//import {Test, console2} from "forge-std/Test.sol";
//import {CyberCorpFactory} from "../src/CyberCorpFactory.sol";
//import {CyberCertPrinter} from "../src/CyberCertPrinter.sol";
//import {IIssuanceManager} from "../src/interfaces/IIssuanceManager.sol";
//import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol";
//import {BorgAuth} from "../src/libs/auth.sol";
//import {CyberAgreementRegistry} from "../src/CyberAgreementRegistry.sol";
//import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol";
//import {IDealManager} from "../src/interfaces/IDealManager.sol";
//import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
//import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
//import {CertificateDetails} from "../src/storage/CyberCertPrinterStorage.sol";
//import "../src/CyberCorpConstants.sol";
//import {CertificateUriBuilder} from "../src/CertificateUriBuilder.sol";
//import {SAFTExtension} from "../src/storage/extensions/SAFTExtension.sol";
//import {IssuanceManager} from "../src/IssuanceManager.sol";
//import {IssuanceManagerWithMigration} from "../src/IssuanceManagerWithMigration.sol";
//import {ILegacyFactory} from "./interfaces/ILegacyFactory.sol";
//import {KnownAddressesLoader} from "./libs/KnownAddressesLoader.sol";
//import {CyberCorp} from "../src/CyberCorp.sol";
//
//contract UpgradeLegacyIssuanceManagersScript is Script {
// function run() public returns (IssuanceManagerWithMigration) {
// return runWithArgs(type(uint256).max);
// }
//
// function runWithArgs(uint256 maxCount) public returns (IssuanceManagerWithMigration) {
// bytes32 salt = bytes32(keccak256("MetaLexCyberCorp.PublicRounds.UpgradeV3.0.2"));
// uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY_MAIN");
//
// CyberCorpFactory cyberCorpFactory = CyberCorpFactory(0x51413048f3Dfc4516e95BC8e249341B1D53B6cB2);
// IssuanceManagerFactory imFactoryV2 = IssuanceManagerFactory(cyberCorpFactory.issuanceManagerFactory()); // this is the v2 one (with reference implementation)
//
// // CyberCertPrinter beacons are owned by each individual IssuanceManagers, so to upgrade them we must
// // enumerate all existing IssuanceManager addresses and their corresponding factories (https://dune.com/queries/6129394):
// // - 0xA32547aAdAA4975082D729c79e79dBaE4385EBCf
// // - 0xade5d9fBaC6201535dc558FBD247e6859f5aa8C5 (deprecated, won't touch it)
// ILegacyFactory legacyImFactory = ILegacyFactory(0xA32547aAdAA4975082D729c79e79dBaE4385EBCf);
//
// // Load all known cyber corps
// address[] memory knownCyberCorps = KnownAddressesLoader.load(block.chainid, "/script/res/known-cyber-corps.json", maxCount);
//
// vm.startBroadcast(deployerPrivateKey);
//
// //
// // Upgrade legacy DealManagers
// //
//
// // Upgrade beacon implementation to the new implementation (with migration feature)
//
// IssuanceManagerWithMigration imWithMigrationImpl = new IssuanceManagerWithMigration();
//
// // Expect new factory to be deployed at a predetermined address because we will hard-code it to the migration contract
// vm.assertEq(cyberCorpFactory.issuanceManagerFactory(), imWithMigrationImpl.NEW_UPGRADE_FACTORY(), "new issuanceManagerFactory address has changed, update it in IssuanceManagerWithMigration");
//
// // Upgrade beacon to a special implementation with migration features
// legacyImFactory.upgradeImplementation(address(imWithMigrationImpl));
// vm.assertEq(legacyImFactory.getBeaconImplementation(), address(imWithMigrationImpl), "beacon implementation should be upgraded with migration features by now");
// console2.log("Set new beacon implementation (with migration features): %s for legacy IssuanceManagerFactory: %s", address(imWithMigrationImpl), address(legacyImFactory));
//
// // This is the ugly part: One-time manual upgrade required for legacy DealManagers.
// // This section updates the `upgradeFactory` pointer to the new permanent factory address,
// // enabling access to updated fee-related methods. This migration is performed one-by-one
// // for each legacy IssuanceManager contract.
//
// // This is a ONE-TIME operation per legacy IssuanceManager's lifetime. Once updated,
// // the `upgradeFactory` is expected to remain permanent and unchanged for all following upgrades.
// for (uint256 i = 0; i < knownCyberCorps.length; i++) {
// address imAddr = CyberCorp(knownCyberCorps[i]).issuanceManager();
// IssuanceManagerWithMigration(imAddr).migrateUpgradeFactory();
// vm.assertNotEq(IssuanceManagerFactory(IssuanceManager(imAddr).getUpgradeFactory()).getRefImplementation(), address(0), "should be able to lookup reference implementation now");
// vm.assertEq(
// IssuanceManager(imAddr).getCertPrinterBeaconImplementation(),
// IssuanceManagerFactory(cyberCorpFactory.issuanceManagerFactory()).getCyberCertPrinterRefImplementation(),
// "should point CyberCertPrinter implementation to reference now"
// );
// vm.assertEq(
// IssuanceManager(imAddr).getScripBeaconImplementation(),
// IssuanceManagerFactory(cyberCorpFactory.issuanceManagerFactory()).getCyberScripRefImplementation(),
// "should point CyberScrip implementation to reference now"
// );
// console2.log("Migrated legacy IssuanceManager: %s", imAddr);
// }
//
// // Upgrade beacon to the normal implementation since migration is done
// address refImplementation = imFactoryV2.getRefImplementation();
// legacyImFactory.upgradeImplementation(refImplementation);
// vm.assertEq(legacyImFactory.getBeaconImplementation(), refImplementation, "beacon implementation should be upgraded without migration features by now");
// console2.log("Set new beacon implementation (without migration features): %s for legacy IssuanceManagerFactory: %s", address(refImplementation), address(legacyImFactory));
//
// vm.stopBroadcast();
//
// return imWithMigrationImpl;
// }
//}
Loading
Loading