NG#4 - 合约地址计算

没有完成入门任务的参考安装入门

Vanity Addresses 是 Cairo 的 CTF 独立任务，类似 Solidity 中的 CREATE2，通过修改 salt 来部署特定前缀后缀的合约地址，再用这个合约去调用目标合约。具体是生成一个开头是 0x04515 的合约地址，去调用下方的 find_oasis 函数。

Copy
fn find_oasis(ref self: ContractState) {
let caller = get_caller_address();
assert(is_oasis(caller), 'NOT_OASIS');
self.is_oasis_found.write(true);
}

部署 hack 合约

StarkNet 上全是合约钱包，所以这题可以部署标准的 AA 钱包账户，也可以单独再写一个合约，不管哪种方式都需要了解 Starknet 的合约是怎么生成的。我采取的方式是编写 hack 合约： AA -> hack 合约 -> find_oasis。

Cairo 中要实现 A 合约调用 B 合约，需要用 DispatcherTrait，可参考 corelib 里的 test_contract.cairo。这个 hack 合约比较简单。

写完后进行合约部署，我采用 StarkNet Book 中推荐的 starkli，如果不清楚流程，metaschool 里有详细教学。大致流程是 scarb build -> starkli declare -> starkli deploy。

需要用 salt=0 去部署 hack.cairo，验证后面计算是否正确，命令是
starkli deploy [classHash] --salt 0 --network=goerli-1

classhash 是 starkli declare 生成的。

deploy 后出现的文字最后一行就是合约地址。接下来需要用任意语言的 SDK 中计算合约的函数去验证 salt=0 时地址是否正确，如果正确就写个循环去找目标 salt。

计算满足条件的合约地址

StarkNet 中的合约地址是通过 pedersen 计算得出的，具体见StarkNet 官方文档：contract_address := pedersen( “STARKNET_CONTRACT_ADDRESS”, deployer_address, salt, class_hash, constructor_calldata_hash)

在 Cario Star 电报群搜索群里，发现 2 个 rust 库可以计算地址：
Option 1: starkli lab https://github.com/xJonathanLEI/starkli/blob/e4d23076b67c05fccc2d7bda069561daaa1fde06/src/subcommands/lab/mine_udc_salt.rs#L37
Option 2: @th0rgal0 's vanity address in their github https://github.com/Th0rgal/vanity-starknet

尝试后发现 starkli lab 不会用，vanity-starknet 只能生成前缀 0x0000... 的地址，所以得找个 SDK 自己写。我采用的是 Starknet.js。

观察之前部署合约的 transaction，starkli deploy其实是调用了 UniversalDeployer (UDC) 合约，这个合约统一负责把 classhash 实例化成新合约。参数需要 classHash, salt, calldata，而 calldata _len 和 unique 应该是 starkli 自动处理的。我部署的 Hack 合约没有构造参数，所以 calldata 是空 array。

很容易在 starknet.js 的库里搜到计算地址的 例子。

本地建一个 nodejs 项目，安装 starknet、jest、typescript 等依赖后，按例子写了测试，发现 salt=0 的地址对不上。

于是又在库里搜其他测试用例，发现当 unique=1 时，计算用的 salt 需要是 hash(deployer, salt)，deployerAddress 是 UDC，才和 starkli 能对上。

代码计算出的地址开头是 0x593c，而部署的是0x0593c，对比时直接去掉一个 0 就行了。也就是需要对比的是"0x4515"而不是"0x04515"。

我在 salt 接近 4 万的时候计算到了需要的值，没做任何优化和多线程，用了 10 多分钟。

更换 salt 后部署的新合约（salt 要转为 hex 再传），得到 Hack 合约地址 0x04515bf8e9d0c....

在本地用 starkli invoke调用 hack 方法后完成任务。

更新：得到 starkli 作者的回答后，starkli lab mine-udc-salt能在几秒内得到结果，具体见 https://github.com/xJonathanLEI/starkli/issues/45#issuecomment-1810015094

总结

除去入门，这是 CTF 的第一题，不算难，但需要熟悉 StarkNet 相关内容。编写合约去解题是 CTF 的常规操作，NG 的题目也不例外，所以需要熟悉合约间的调用。另外本题也开始接触到了 SDK 的使用，部分操作需要链下计算。