Skip to content

Conversation

@md0x
Copy link
Contributor

@md0x md0x commented Dec 3, 2024

Changes Proposed in this PR:

This PR introduces scripts to manage the full lifecycle of a rootBundle workflow for rebalancing USDC between the SVM Spoke Pool and the Hub Pool on mainnet. The process includes proposing a rootBundle, executing it after the liveness period, bridging via CCTP, and handling liabilities. The workflow is divided into three scripts:

  • proposeRebalanceToHubPool: Proposes the rebalance from the Spoke Pool to the Hub Pool in the Hub Pool.
  • executeRebalanceToHubPool: Executes the approved rebalance in the Hub Pool, bridges it via CCTP to the Spoke Pool, and processes the relayer refund leaf to create the liability.
  • bridgeLiabilityToHubPool: Bridges any pending liability from the SVM Spoke Pool back to the Hub Pool via CCTP.

md0x added 6 commits December 3, 2024 09:50
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
@md0x md0x changed the title feat: add propose rebalance to hub pool script feat: rebalance to hub pool script Dec 3, 2024
md0x added 3 commits December 4, 2024 12:19
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
@md0x md0x marked this pull request as ready for review December 4, 2024 12:29
@md0x md0x requested review from Reinis-FRP and chrismaree December 4, 2024 12:29
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Comment on lines 9 to 10
export const SEPOLIA_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238";
export const MAINNET_USDC_ADDRESS = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better reuse TOKEN_SYMBOLS_MAP as exported in utils/constants.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean doing this?
c17299c

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kindof, but better avoid putting the var in constants and not pass chainId. E.g. can pull required token for required chain dynamically, like here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right. I fixed it here: 10a60f2

const tx = await hubPool.connect(ethersSigner).proposeRootBundle(
[0], // bundleEvaluationBlockNumbers, not checked in this script.
1, // poolRebalanceLeafCount, only one leaf in this script.
poolRebalanceTree.getHexRoot(), // poolRebalanceRoot.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is pool rebalance needed, cannot it be zero hash?

Copy link
Contributor Author

@md0x md0x Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven’t been able to do it with a zero hash in the poolRebalanceTree. I think we need to pass at least a tree with one leaf; the leaf can be constructed with zero hashes, except for the chain ID. Otherwise, we cannot get past this line when calling executeRootBundle:

// Verify the props provided generate a leaf that, along with the proof, are included in the merkle root.
require(
MerkleLib.verifyPoolRebalance(
rootBundleProposal.poolRebalanceRoot,
PoolRebalanceLeaf({
chainId: chainId,
groupIndex: groupIndex,
bundleLpFees: bundleLpFees,
netSendAmounts: netSendAmounts,
runningBalances: runningBalances,
leafId: leafId,
l1Tokens: l1Tokens
}),
proof
),
"Bad Proof"
);

Additionally, the chain ID needs to be valid; otherwise, this line fails:

(address adapter, address spokePool) = _getInitializedCrossChainContracts(chainId);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, yes, you're totally right on this!

md0x added 3 commits December 4, 2024 16:13
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
@md0x md0x requested a review from Reinis-FRP December 5, 2024 09:25
}

// Run the bridgeLiabilityToHubPool function
bridgeLiabilityToHubPool();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this script is SUPER useful. This will basically be what the finalizer needs to do in production.

]);

const [transferLiability] = PublicKey.findProgramAddressSync(
[Buffer.from("transfer_liability"), new PublicKey(svmUsdc).toBuffer()],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only comment I could make on this script (but I think it's fine as we do similar things all over the place) is this assumes we are working with USDC.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in many places we have dependencies on USDC, including in our smart contracts (solana adapter) and svm programs. Do you think it’s worth generalizing?

Comment on lines 4 to 7
* This script executes a previously proposed root bundle on the Hub Pool
* to rebalance USDC from the Solana Spoke Pool to the Ethereum Hub Pool.
* It handles CCTP attestations, relayer refund leaf execution, and prepares
* pending liabilities for bridging back to the Hub Pool.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just an irritating nit that like with the other scripts we have 120 chars to work with so we don't need to wrap shorter than 120.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

* anchor run executeRebalanceToHubPool \
* --provider.cluster "devnet" \
* --provider.wallet $SOLANA_PKEY_PATH \
* -- --netSendAmount 7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this is provided to re-construct the merkle leaf & proof? it also assumes that there are no relayer repayments within the leaf, right?

in practice, I don't think this is how this flow will work, right? it's assumed that the data worker will post the leafs & proofs to a public location so these can be retrieved. this particular script flow is only useful in this particular situation where you don't have any relayer repayments & we only do a net repayment.

It would be useful to be able to pass in the leafs as en env/json or something like this? this would let you take them from the script that does the proposing, save them, and then not need to re-generate them. it would also better track with what things will look like when we interface with the data worker later (executor should not need to generate leafs, just get given them)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(prehaps this is still useful if we are dealing with JUST creating leafs to pull/push tokens to/from SVM via the netSendAmount

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. The netSendAmount is merely to avoid having to pass leaves, roots, proofs, etc., between this script and proposeRebalanceToHubPool.ts. It also assumes that the poolRebalanceTree has a single leaf with empty data and the solanaChainId. Thus, both scripts are dependent on each other. I believe they do not showcase a real production scenario; they are more like helpers to test the rebalance from the SVM Spoke to the HubPool.

On the other hand, I separated bridgeLiabilityToHubPool.ts from them because this one could represent a real use case, as you pointed out. It’s essentially what the finalizer needs to do.

Signed-off-by: Pablo Maldonado <pablomaldonadoturci@gmail.com>
@md0x md0x requested a review from chrismaree December 5, 2024 12:45
@md0x md0x merged commit 550ca5e into master Dec 5, 2024
9 checks passed
@md0x md0x deleted the pablo/rebalance-to-hub-pool branch December 5, 2024 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants