from web3 import Web3
CCIP = "0x6F2A3D35Ff275d6B76dB47eFB0Da1b2358daf11b"
USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
SAFE_CONFIG = [{"name": "owners", "type": "address[]"}, {"name": "threshold", "type": "uint256"}]
ASSET_CONFIG = [{"name": "asset", "type": "address"}, {"name": "canDeposit", "type": "bool"}, {"name": "canRedeem", "type": "bool"}]
PARAMS = [
{"name": "asset", "type": "address"}, {"name": "admin", "type": "address"},
{"name": "name", "type": "string"}, {"name": "symbol", "type": "string"}, {"name": "safe", "type": "address"},
{"name": "subscriptionRequestTtl", "type": "uint64"}, {"name": "redemptionRequestTtl", "type": "uint64"},
{"name": "feeReceiver", "type": "address"}, {"name": "managementFeeRate", "type": "uint256"},
{"name": "redemptionFeeRate", "type": "uint256"}, {"name": "performanceFeeModule", "type": "address"},
{"name": "performanceFeeRate", "type": "uint256"},
]
OIV_CONFIG = {"name": "config", "type": "tuple", "components": [
{"name": "managerSafe", "type": "tuple", "components": SAFE_CONFIG},
{"name": "salt", "type": "uint256"}, {"name": "admin", "type": "address"},
{"name": "sharesParams", "type": "tuple", "components": PARAMS},
{"name": "additionalAssets", "type": "tuple[]", "components": ASSET_CONFIG},
]}
OIV_INSTANCE = [{"name": n, "type": "address"} for n in
["avatarSafe", "managerSafe", "execRolesModifier", "subRolesModifier",
"managerRolesModifier", "kpkSharesImpl", "kpkSharesProxy"]]
ABI = [
{"name": "predictOiv", "type": "function", "stateMutability": "view",
"inputs": [OIV_CONFIG], "outputs": [{"name": "", "type": "tuple", "components": OIV_INSTANCE}]},
{"name": "quoteDeployEverywhere", "type": "function", "stateMutability": "view",
"inputs": [OIV_CONFIG, {"name": "gasLimit", "type": "uint256"}],
"outputs": [{"name": "totalFee", "type": "uint256"}, {"name": "feePerDestination", "type": "uint256[]"}]},
{"name": "deployEverywhere", "type": "function", "stateMutability": "payable",
"inputs": [OIV_CONFIG, {"name": "gasLimit", "type": "uint256"}],
"outputs": [{"name": "instance", "type": "tuple", "components": OIV_INSTANCE},
{"name": "messageIds", "type": "bytes32[]"}]},
]
config = (
(["0x1111...", "0x2222...", "0x3333..."], 2), # managerSafe (owners, threshold)
1, # salt
"0xAdminSafe...", # admin
(USDC, "0x" + "0" * 40, "KPK USD Alpha", "kUSD", "0x" + "0" * 40,
86400, 86400, "0xFeeReceiver...", 100, 0, "0x" + "0" * 40, 0), # sharesParams
[], # additionalAssets
)
GAS_LIMIT = 1_800_000
w3 = Web3(Web3.HTTPProvider("https://eth.llamarpc.com"))
orchestrator = w3.eth.contract(address=CCIP, abi=ABI)
predicted = orchestrator.functions.predictOiv(config).call()
print("Portfolio Safe will be:", predicted[0]) # avatarSafe
total_fee, _ = orchestrator.functions.quoteDeployEverywhere(config, GAS_LIMIT).call()
# Deploy (mainnet only): build, sign, and send with value = total_fee
acct = w3.eth.account.from_key("0x<PRIVATE_KEY>")
tx = orchestrator.functions.deployEverywhere(config, GAS_LIMIT).build_transaction({
"from": acct.address, "value": total_fee, "nonce": w3.eth.get_transaction_count(acct.address),
})
signed = acct.sign_transaction(tx)
print("deployEverywhere tx:", w3.eth.send_raw_transaction(signed.raw_transaction).hex())