Skip to content

Commit

Permalink
Merge branch 'master' into refactor/deriver
Browse files Browse the repository at this point in the history
  • Loading branch information
szhygulin authored May 22, 2024
2 parents 121406e + 7cfc963 commit 0d6e796
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 31 deletions.
11 changes: 10 additions & 1 deletion script/SetSeed.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,32 @@ import {BTCDepositAddressDeriver} from "../src/BTCDepositAddressDeriver.sol";

contract SetSeed is Script {
function run() external {
// get contract address
address contractAddress = DevOpsTools.get_most_recent_deployment(
"BTCDepositAddressDeriver",
block.chainid
);
console.log("contractAddress", contractAddress);

// get first validators' joint pubkey
string memory btcAddr1 = vm.envString("BTC_ADDR1");
console.log("BTC_ADDR1:", btcAddr1);

// get second validators' joint pubkey
string memory btcAddr2 = vm.envString("BTC_ADDR2");
console.log("BTC_ADDR2:", btcAddr2);

// get network
uint network = vm.envUint("Network");
console.log("Network:", network);

BTCDepositAddressDeriver deriver = BTCDepositAddressDeriver(
contractAddress
);

// set validators' pubkeys and network prefix
vm.startBroadcast();
deriver.setSeed(btcAddr1, btcAddr2, "bcrt");
deriver.setSeed(btcAddr1, btcAddr2, BTCDepositAddressDeriver.BitcoinNetwork(network));
vm.stopBroadcast();
}
}
90 changes: 68 additions & 22 deletions src/BTCDepositAddressDeriver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,35 @@ import {Deriver} from "./Deriver.sol";
import {Bech32m} from "./Bech32m.sol";

error SeedWasNotSetYet();

error UnsupportedBtcAddress(string btcAddress);
error CannotParseBtcAddress(
string btcAddress,
string hrp,
Bech32m.DecodeError err
);
error UnsupportedBtcAddress(string btcAddress);

// Types of Bitcoin Network

contract BTCDepositAddressDeriver {

enum BitcoinNetwork {
TESTNET,
MAINNET,
REGTEST
}

event SeedChanged(string btcAddr1, string btcAddr2, string hrp);

bool public wasSeedSet;

// Validators' joint pubkeys in format of taproot addresses
string public btcAddr1;
string public btcAddr2;

// Bitcoin address's network prefix
string public networkHrp;

// Validators' pubkey both coordinates deconstructed from taproot addresses
uint256 public p1x;
uint256 public p1y;
uint256 public p2x;
Expand All @@ -31,48 +44,81 @@ contract BTCDepositAddressDeriver {
wasSeedSet = false;
}

// Set Validators' joint pubkeys and network prefix, must be called after contract deployment
function setSeed(
string calldata _btcAddr1,
string calldata _btcAddr2,
BitcoinNetwork _network
) public virtual {

string memory _hrp = getNetworkPrefix(_network);

networkHrp = _hrp;

(p1x, p1y) = parseBTCTaprootAddress(_hrp, _btcAddr1);
(p2x, p2y) = parseBTCTaprootAddress(_hrp, _btcAddr2);

btcAddr1 = _btcAddr1;
btcAddr2 = _btcAddr2;

wasSeedSet = true;
emit SeedChanged(_btcAddr1, _btcAddr2, _hrp);
}

// get address prefix from network type
function getNetworkPrefix(
BitcoinNetwork _network
) public pure returns (string memory) {

string memory _hrp;

if (_network == BitcoinNetwork.TESTNET) {
_hrp = 'tb';
} else if (_network == BitcoinNetwork.MAINNET) {
_hrp = 'bc';
} else if (_network == BitcoinNetwork.REGTEST) {
_hrp = 'brct';
}

return _hrp;
}

// Derive pubkey's (x,y) coordinates from taproot address
function parseBTCTaprootAddress(
string calldata hrp,
string calldata addr
string memory _hrp,
string calldata _bitcoinAddress
) public pure returns (uint256, uint256) {

(uint8 witVer, bytes memory witProg, Bech32m.DecodeError err) = Bech32m
.decodeSegwitAddress(bytes(hrp), bytes(addr));
.decodeSegwitAddress(bytes(_hrp), bytes(_bitcoinAddress));

if (err != Bech32m.DecodeError.NoError) {
revert CannotParseBtcAddress(addr, hrp, err);
revert CannotParseBtcAddress(_bitcoinAddress, _hrp, err);
}
if (witVer != 1 || witProg.length != 32) {
revert UnsupportedBtcAddress(addr);
revert UnsupportedBtcAddress(_bitcoinAddress);
}

uint256 x = uint256(bytes32(witProg));

if (x == 0 || x >= Deriver.PP) {
revert UnsupportedBtcAddress(addr);
revert UnsupportedBtcAddress(_bitcoinAddress);
}

uint256 y = Deriver.liftX(x);

return (x, y);
}

function setSeed(
string calldata _btcAddr1,
string calldata _btcAddr2,
string calldata _hrp
) public virtual {
networkHrp = _hrp;
(p1x, p1y) = parseBTCTaprootAddress(_hrp, _btcAddr1);
(p2x, p2y) = parseBTCTaprootAddress(_hrp, _btcAddr2);
btcAddr1 = _btcAddr1;
btcAddr2 = _btcAddr2;
wasSeedSet = true;
emit SeedChanged(_btcAddr1, _btcAddr2, _hrp);
}

// Get users' Bitcoin deposit address from user's Ethereum address
function getBTCDepositAddress(
address ethAddr
) public view returns (string memory) {

if (!wasSeedSet) {
revert SeedWasNotSetYet();
}

return
Deriver.getBtcAddressFromEth(
p1x,
Expand Down
12 changes: 4 additions & 8 deletions test/BTCDepositAddressDeriver.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ import {Test} from "forge-std/Test.sol";
import {BTCDepositAddressDeriver} from "../src/BTCDepositAddressDeriver.sol";

contract BTCDepositAddressDeriverTest is Test {
BTCDepositAddressDeriver deriver;

// Due to a bug/feature of Solidity, it is impossible to import events from other contract.abi
// https://github.com/ethereum/solidity/issues/13928
// It is copy-pasted here from src/BTCDepositAddressDeriver.sol
event SeedChanged(string btcAddr1, string btcAddr2, string hrp);
BTCDepositAddressDeriver deriver;

function setUp() public {
deriver = new BTCDepositAddressDeriver();
Expand Down Expand Up @@ -58,15 +54,15 @@ contract BTCDepositAddressDeriverTest is Test {
assertEq(deriver.p2y(), 0);

vm.expectEmit(address(deriver));
emit SeedChanged(
emit BTCDepositAddressDeriver.SeedChanged(
"tb1p7g532zgvuzv8fz3hs02wvn2almqh8qyvz4xdr564nannkxh28kdq62ewy3",
"tb1psfpmk6v8cvd8kr4rdda0l8gwyn42v5yfjlqkhnureprgs5tuumkqvdkewz",
"tb"
);
deriver.setSeed(
"tb1p7g532zgvuzv8fz3hs02wvn2almqh8qyvz4xdr564nannkxh28kdq62ewy3",
"tb1psfpmk6v8cvd8kr4rdda0l8gwyn42v5yfjlqkhnureprgs5tuumkqvdkewz",
"tb"
BTCDepositAddressDeriver.BitcoinNetwork.TESTNET
);

assertEq(deriver.wasSeedSet(), true);
Expand Down Expand Up @@ -101,7 +97,7 @@ contract BTCDepositAddressDeriverTest is Test {
deriver.setSeed(
"tb1p7g532zgvuzv8fz3hs02wvn2almqh8qyvz4xdr564nannkxh28kdq62ewy3",
"tb1psfpmk6v8cvd8kr4rdda0l8gwyn42v5yfjlqkhnureprgs5tuumkqvdkewz",
"tb"
BTCDepositAddressDeriver.BitcoinNetwork.TESTNET
);

string memory btcAddress = deriver.getBTCDepositAddress(
Expand Down

0 comments on commit 0d6e796

Please sign in to comment.