diff --git a/README.md b/README.md index a68b9d0..fe150ab 100644 --- a/README.md +++ b/README.md @@ -7,43 +7,82 @@ and uses them to buy and retire carbon credits via Toucan. The resultant Retirement Certificate is then bridged back to Solana. -## Instructions +## Process Description -Note: This is a work in progress, and these steps will change as the project evolves. +1. Depositing into a token authority account on Solana +A token authority account is an account on Solana where users can deposit funds into that which go through the offset bridge to retire carbon credits. The token authority account is a PDA owned by the swap-bridge program and specified through a state account on Solana. Within the state account, a holding contract on polygon, to which the fund from solana will be bridged to, is specified. Each holding contract is generated for a specific NCT carbon project and a specific Solana wallet to which the retirement certificate will be stored at the end of the process. -1. Initialize +Hence each token authority account corresponds to a specific carbon project and a specific Solana wallet. Therefore, each user should create their own token authority account if they would like the retirement certificate to be sent back to their own wallet. -```shell -yarn initialize -``` +2. Swapping into wrapped USDC (USDCpo) +The fund in the token authority account will then be swapped into USDCpo on a DEX (Jupiter is used currently). This is done such that the funds can be sent to Polygon to buy and retire NCT carbon credits, which are on the Polygon chain. -Sets up a new State on solana and derives a Token Authority PDA. -This should be done only once. +3. Bridging into a holding contract on Polygon +The USDCpo now in the token authority account will be sent to Polygon via the Wormhole bridge in this step. The bridged fund will land as USDC on the holding contract that is associated with the token authority account. Shall it happen that the user wish to bridge the funds existing in the token authority account to a different account on Polygon, it is possible with the signature of the update authority. -2. Wrap SOL +4. Retiring carbon credits +In this step the USDC now in the holding contract will be used to buy NCT carbon credits through a DEX (Sushi Swap is used in this step currently). The NCT carbon credits will then be sent to a retirement contract where TCO2 will be retired and a retirement certificate will be minted at the same time. The beneficiary of the retirement certificate is -```shell -yarn wrap-sol -``` +5. Bridging back to Solana +The retirement certificate will be bridged back to Solana to the wallet specified in the state account that is associated with the token authority account in the first step. -Transfers SOL to the Solana "Token Authority" PDA -NOTE: this step will later be moved into the smart contract, so you can simply call the smart contract with SOL. -NOTE 2: When paying with an SPL Token like USDC, this step can be skipped +## UI +A user interface is available for going through the above process easily, the UI consists on the following pages: -3. Swap SOL for USDCpo +1. Step 1 -- Select Account +In this page the user can connect with their own Solana and Polygon wallets. The Solana wallet should contain either the SOL or USDC which are going to be used to buy the NCT carbon tokens. The Polygon wallet should contain enough Matic for paying transaction fees needed in the later steps. -```shell -yarn swap -``` +A default carbon project is displayed on screen but users can also pick their own carbon project to retire credits for by clicking the button `Change`. As of now, you can choose from multiple Toucan projects/carbon offsets. In the future, more projects from other third parties will be accessible via Sunrise Stake’s offset bridge. -4. Bridge USDCpo to Polygon and receive USDC in Holding Contract +![step1b.png](docs/step1b.png) +![step1c.png](docs/step1c.png) -```shell -yarn bridge -``` +As an example, let us pick [VCS875 2015](https://registry.verra.org/app/projectDetail/VCS/875), a REDD+ (“_Reducing Emissions from Deforestation and forest Degradation_”) project which is also offered by Regen Network. Once you have selected a project, you can see how many credits are still available to be acquired and retired. -5. Use the funds to retire carbon tokens on Toucan -```shell -yarn retire -``` \ No newline at end of file +![step1d.png](docs/step1d.png) + +**As of now, the UI does not prevent you from committing more funds to a project, than it has credits left for you to retire and it is not possible to bridge left over funds back, so please double-check.** In future updates, the UI will prevent you from committing more funds than you can actually spend on any carbon project. + +After the wallets are connected and the carbon project specified. User can click `Setup Solana side` to set up the token authority account (which is associated with a holding contract owned by the connected Polygon wallet). + +2. Step 2 -- Deposit +In this page the user can choose to deposit either USDC or SOL into the token authority account. If you would like to specify the amount of metric tons of carbon you want to retire rather than the amount of SOL or USDC you would like to be spent, you can use the toggle and switch from “SOL” to “carbon”. + +![step2a.png](docs/step2a.png) + +After specifying the amount of SOL/USDC to deposit, users can click `Deposit and Swap` to perform both the action of depositing the SOL/USDC from the Solana wallet to the token authority account and swapping the deposited amount into wrapped USDC (USDCpo) on the DEX (Jupiter). The amount of tCO2 that could be retired with the deposited amount will be displayed in bracket. + +Effectively, when you send funds into the state contract on Solana, you are committing them to solely be spent in the holding contract on Polygon. This holding contract specifies the respective carbon project you choose to retire carbon offsets against. Once you have committed funds to the state account on Solana, it can only be spent by the holding account on Polygon for the carbon project you have chosen. + + +3. Step 3 -- Bridge +The total amount existing in the token authority account will be displayed on this page. The user can check if it's the expected amount before clicking `Bridge` to send the USDCpo from the token authority account to the bridge (Wormhole). + +![step3a.png](docs/step3a.png) + +After the amount has been sent sucessfully to the bridge, the `Redeem` button will turn green and the user can then click on it to redeem the sent USDCpo onto the holding contract on the Polygon chain to finish the bridging action. + +![step3b.png](docs/step3b.png) + +4. Step 4 -- Retire +Now that the USDCs are in the holding contract, it is ready to be used to retire carbon credit. In this page users would just need to click `Retire` and all the USDCs in the holding contract will be used to retire carbon credits from the selected carbon project in Step 1. An NFT will be minted at the same time that represent the retirement certificate. + +![step4a.png](docs/step4a.png) + +5. Step 5 -- Redeem Retirement Certificate +The retirement certificate can be bridged back to the user's Solana wallet. Similar to Step 3, the user would have to first click `Bridge` to send the NFT to the bridge and then once the NFT is sent to the bridge, the user can click the `Redeem` button to redeem it onto their Solana wallet. + +![step5a.png](docs/step5a.png) + +This might take a few minutes or hours, as Wormhole slows down bridging assets from Polygon for security reasons. After that, you can redeem the certificate on Solana by pressing the respective button and confirming the transactions in your Solana wallet and go to the last step by clicking “next”. + +![step5b.png](docs/step5b.png) + +6. Step 6 -- Retirement Certificate +On this page all the exisiting Toucan retirement certificates in the user's Solana wallet will be displayed, a new retirement certificate should be shown after going through the above steps. To see the metadata of the retirement certificate, you can click on the hyperlink in the “View” page. + +![step6a.png](docs/step6a.png) +![step6b.png](docs/step6b.png) + +Congratulations! You have successfully offset some carbon and bridged the retirement proof onto Solana. \ No newline at end of file diff --git a/docs/step1b.png b/docs/step1b.png new file mode 100644 index 0000000..a5b2a5a Binary files /dev/null and b/docs/step1b.png differ diff --git a/docs/step1c.png b/docs/step1c.png new file mode 100644 index 0000000..79bd13f Binary files /dev/null and b/docs/step1c.png differ diff --git a/docs/step1d.png b/docs/step1d.png new file mode 100644 index 0000000..1ac1590 Binary files /dev/null and b/docs/step1d.png differ diff --git a/docs/step2a.png b/docs/step2a.png new file mode 100644 index 0000000..d997486 Binary files /dev/null and b/docs/step2a.png differ diff --git a/docs/step3a.png b/docs/step3a.png new file mode 100644 index 0000000..3ccb985 Binary files /dev/null and b/docs/step3a.png differ diff --git a/docs/step3b.png b/docs/step3b.png new file mode 100644 index 0000000..9060bb0 Binary files /dev/null and b/docs/step3b.png differ diff --git a/docs/step4a.png b/docs/step4a.png new file mode 100644 index 0000000..ddbfd21 Binary files /dev/null and b/docs/step4a.png differ diff --git a/docs/step5a.png b/docs/step5a.png new file mode 100644 index 0000000..0b8d030 Binary files /dev/null and b/docs/step5a.png differ diff --git a/docs/step5b.png b/docs/step5b.png new file mode 100644 index 0000000..441df54 Binary files /dev/null and b/docs/step5b.png differ diff --git a/docs/step6a.png b/docs/step6a.png new file mode 100644 index 0000000..baa799d Binary files /dev/null and b/docs/step6a.png differ diff --git a/docs/step6b.png b/docs/step6b.png new file mode 100644 index 0000000..bf4e071 Binary files /dev/null and b/docs/step6b.png differ diff --git a/evm-contract/src/CarbonOffsetSettler.sol b/evm-contract/src/CarbonOffsetSettler.sol index 5e32825..f35d240 100644 --- a/evm-contract/src/CarbonOffsetSettler.sol +++ b/evm-contract/src/CarbonOffsetSettler.sol @@ -10,6 +10,9 @@ import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol"; import "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/IERC721Upgradeable.sol"; import "forge-std/console.sol"; +/** + * @notice This contract is to be used to purchase and offset carbon credits + */ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { address public constant NCT = 0xD838290e877E0188a4A44700463419ED96c16107; address public constant CERT = 0x5e377f16E4ec6001652befD737341a28889Af002; @@ -19,18 +22,15 @@ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { uint public tokenId; - // function initialize( - // address newholdingContract, - // address sunriseAdmin - // ) external { - // transferOwnership(sunriseAdmin); - // holdingContract = newholdingContract; - // } - - // function setHoldingContract(address newHoldingContract) external onlyOwner { - // holdingContract = newHoldingContract; - // } - + /** + * Retire carbon credits from specified project for a specified amount of USDC + * @param _tco2 Address of the project for which TCO2 will be retired + * @param _amountUSDC Amount of USDC to be used to buy carbon credits + * @param _entity Name of the entity who is performing the retirement + * @param _beneficiary Address of beneficiary, to whom the retirement will be accredited + * @param _beneficiaryName Name of beneficiary + * @param _msg Any message to be attached to the retirement certificate + */ function retire( address _tco2, uint256 _amountUSDC, @@ -72,7 +72,7 @@ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { ); } - /* + /** * @notice Called when new Toucan retirement certificate NFTs are minted. */ function onERC721Received( @@ -85,9 +85,10 @@ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { return IERC721Receiver.onERC721Received.selector; } - /* - * Given a specific TCO2 and amount, return the amount of xUSDC we would - * need to burn after fees. + /** + * Given a specific TCO2 and amount, return the amount of xUSDC we would need to burn after fees. + * @param _tco2 Address of the project for which TCO2 will be retired + * @param _amountToOffset Amount of TCO2 to offset */ function getUSDCNeeded( address _tco2, @@ -111,9 +112,10 @@ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { return expectedAmountsIn[0]; } - /* - * Given a specific TCO2 and amount, return the amount of xUSDC we would - * need to burn after fees. + /** + * Given a specific TCO2 and amount, return the amount of NCT we would need to burn after fees. + * @param _tco2 Address of the project for which TCO2 will be retired + * @param _amountToOffset Amount of TCO2 to offset */ function getExpectedNCT( address _tco2, @@ -135,8 +137,10 @@ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { return expectedAmountsIn[0]; } - /* - * Only support USDC <-> NCT routes + /** + * Find path for swapping; only support USDC <-> NCT routes + * @param _from Address of token to be swapped from + * @param _to Address of token to be swapped to */ function generatePath( address _from, @@ -150,6 +154,7 @@ contract CarbonOffsetSettler is OwnableUpgradeable, IERC721Receiver { /** * Swap USDC on contract into NCT. + * @param _amountUSDC Amount of USDC to swap for NCT tokans */ function swap(uint256 _amountUSDC) public returns (uint256) { IUniswapV2Router02 routerSushi = IUniswapV2Router02(SUSHI_ROUTER); diff --git a/evm-contract/src/HoldingContract.sol b/evm-contract/src/HoldingContract.sol index e477964..2253067 100644 --- a/evm-contract/src/HoldingContract.sol +++ b/evm-contract/src/HoldingContract.sol @@ -12,6 +12,10 @@ import "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/IERC721Upg import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol"; import "lib/openzeppelin-contracts/contracts/utils/Counters.sol"; +/** + * A holding contract that holds the bridged funds from a Solana account, use it to buy and retire TCO2, + * and send the retirement certificate back to the Solana address + */ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { // Logic contract address // address public logicContract; @@ -37,7 +41,13 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { // USDC token contract address public constant USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; - // Event emitted when funds are used to offset emissions + /** + * Event emitted when funds are used to offset emissions + * @param tco2 Address of the project for which TCO2 will be retired + * @param beneficiary Address of beneficiary, to whom the retirement will be accredited + * @param beneficiaryName Name of beneficiary + * @param amount Amount of TCO2 offset + */ event Offset( address indexed tco2, address indexed beneficiary, @@ -49,8 +59,15 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { error InsufficientFunds(); error InvalidRetireContract(); - /* + /** + * To initialize a holding contract with a new set of parameters * @notice Initialize the proxy contract + * @param newTco2 Address of the project for which TCO2 will be retired + * @param newBeneficiary Address of beneficiary, to whom the retirement will be accredited + * @param newBeneficiaryName Name of beneficiary + * @param newSolanaAccountAddress Address of wallet in Solana to which the retirement certificate will be sent to + * @param newRetireContract Address of the deployed contract of CarbonOffsetSettler to be used to retire TCO2 + * @param owner Address of owner of the holding contract */ function initialize( address newTco2, @@ -70,22 +87,18 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { transferOwnership(owner); } - /* + /** * @notice Set the address of the CarbonOffsetSettler contract - * @param newRetireContract address of the CarbonOffsetSettler contract + * @param newRetireContract Address of the CarbonOffsetSettler contract */ function setRetireContract(address newRetireContract) external onlyOwner { if (newRetireContract == address(0)) revert InvalidRetireContract(); retireContract = newRetireContract; } - // function setFactoryContract(address newFactoryContract) external onlyOwner { - // factoryContract = newFactoryContract; - // } - // ------------------ Setting retirement details (admin-only, ensure valid values) ------------------ // - /* + /** * @notice Set the details for the beneficiary of the carbon offset * @param newBeneficiary address of the beneficiary (in case you're retiring for someone else) * @param newBeneficiaryName name of the beneficiary @@ -98,7 +111,7 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { beneficiaryName = newBeneficiaryName; } - /* + /** * @notice Set the address of the TCO2 token contract * @param newTco2 address of the TCO2 token contract */ @@ -118,7 +131,7 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { } // --------------------------------- Permissionless retiring --------------------------------------- // - /* + /** * @notice Offset carbon emissions by sending USDC to the CarbonOffsetSettler contract and using the funds to retire carbon tokens. * @param entity name of the entity that does the retirement (Sunrise Stake) * @param message retirement message @@ -158,7 +171,7 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { _bridgeNFT(tokenId); } - /* + /** * @dev Necessary to receive ERC721 transfers */ function onERC721Received( @@ -170,7 +183,7 @@ contract HoldingContract is OwnableUpgradeable, IERC721Receiver { return IERC721Receiver.onERC721Received.selector; } - /* + /** * @notice Set the Solana Account that receives the retirement certificate * @dev This is read out to calculate the associated token account for the Wormhole message * @param newSolanaAccountAddress address of the Solana Account diff --git a/evm-contract/src/HoldingContractFactory.sol b/evm-contract/src/HoldingContractFactory.sol index b1382ad..421d082 100644 --- a/evm-contract/src/HoldingContractFactory.sol +++ b/evm-contract/src/HoldingContractFactory.sol @@ -6,6 +6,9 @@ import "src/HoldingContract.sol"; import "forge-std/console.sol"; import "lib/openzeppelin-contracts/contracts/access/Ownable.sol"; +/** + * @notice Factory to generate holding contracts + */ contract HoldingContractFactory is Ownable { address public implementationAddress; address[] public proxies; @@ -16,12 +19,24 @@ contract HoldingContractFactory is Ownable { implementationAddress = newImplementationAddress; } + /** + * @notice Set the implementation address for a holding contract + * @param newImplementationAddress Address of the implementation of a holding contract + */ function setImplementationAddress( address newImplementationAddress ) external onlyOwner { implementationAddress = newImplementationAddress; } + /** + * Create a new holding contract + * @param salt Salt for determining the address of new holding contract + * @param newTco2 Address of the project for which TCO2 will be retired + * @param newBeneficiaryName Name of beneficiary + * @param newSolanaAccountAddress Address of wallet in Solana to which the retirement certificate will be sent to + * @param retireContract Address of the deployed contract of CarbonOffsetSettler to be used to retire TCO2 + */ function createContract( bytes32 salt, address newTco2, @@ -47,9 +62,9 @@ contract HoldingContractFactory is Ownable { } /** - * @dev Returns the address of the implementation given a particular salt - * @return The address of the implementation. - */ + * @dev Returns the address of the implementation given a particular salt + * @return The address of the implementation. + */ function getContractAddress( bytes32 salt, address deployer diff --git a/solana-contract/programs/swap-bridge/src/lib.rs b/solana-contract/programs/swap-bridge/src/lib.rs index d4952df..2bb20e5 100644 --- a/solana-contract/programs/swap-bridge/src/lib.rs +++ b/solana-contract/programs/swap-bridge/src/lib.rs @@ -11,6 +11,8 @@ declare_id!("suobUdMc9nSaQ1TjRkQA4K6CR9CmDiU9QViN7kVw74T"); #[program] pub mod swap_bridge { + /// Program to swap SOL or USDC to a wrapped USDC token (e.g. USDCpo) + /// and bridge it over to the chain where carbon tokens are to be bought and retired (e.g. Polygon) using Wormhole use super::*; use crate::util::bridge::call_bridge; use crate::util::errors::ErrorCode; @@ -23,6 +25,17 @@ pub mod swap_bridge { state_in: GenericStateInput, _state_index: u8, ) -> Result<()> { + /* Initialise the state account with specific parameters + + Parameters + ---------- + state_in: GenericStateInput specifying the content of the state account, including: + state_in.output_mint: the output mint of the target token (e.g. USDCpo) + state_in.holding_contract: the holding contract address on target chain + state_in.token_chain_id: the Wormhole ID of the target chain + state_in.update_authority: an account with the authority to update these parameters of the state account + _state_index: index to differentiate different # of state accounts belonging to the same wallet + */ ctx.accounts.state.output_mint = state_in.output_mint; ctx.accounts.state.holding_contract = state_in.holding_contract; ctx.accounts.state.token_chain_id = state_in.token_chain_id; @@ -32,7 +45,17 @@ pub mod swap_bridge { } pub fn update_state(ctx: Context, state_in: GenericStateInput) -> Result<()> { - // update state account parameters + /* Update state account parameters + + Parameters + ---------- + state_in: GenericStateInput specifying the content of the state account, including: + state_in.output_mint: the output mint of the target token (e.g. USDCpo) + state_in.holding_contract: the holding contract address on target chain + state_in.token_chain_id: the Wormhole ID of the target chain + state_in.update_authority: an account with the authority to update these parameters of the state account + _state_index: index to differentiate different # of state accounts belonging to the same wallet + */ let state = &mut ctx.accounts.state; state.update_authority = state_in.update_authority; state.output_mint = state_in.output_mint; @@ -57,9 +80,16 @@ pub mod swap_bridge { } pub fn swap(ctx: Context, route_info: Vec) -> Result<()> { + /* Swap SOL for wrapped USDC for the target chain using Jupiter + + Parameters + ---------- + route_info: data for instructions from Jupiter specifying the route for swapping + */ let mut router_accounts = vec![]; let state_address = ctx.accounts.state.key(); let (token_authority, token_authority_bump) = State::get_token_authority(&state_address); + // Set token_authority to be a signer for account in ctx.remaining_accounts { let is_signer = account.key == &token_authority; router_accounts.push(if account.is_writable { @@ -91,7 +121,16 @@ pub mod swap_bridge { amount: u64, bridge_data: Vec, ) -> Result<()> { + /* Brige a specified amount of wrapped USDC to target chain via Wormwhole + + Parameters + ---------- + amount: amount to bridge over + bridge_data: data for bridging instructions from Wormhole + */ let state_address = ctx.accounts.state.key(); + // Deserialise bridge_data to check if the recipient address on the target chain + // is the same as the holding contract address specified in the state let deserialised_bridge_data = TransferWrapped::deserialize(&mut bridge_data.as_ref()).unwrap(); msg!( @@ -139,6 +178,7 @@ pub mod swap_bridge { #[derive(Accounts)] #[instruction(state_in: GenericStateInput, state_index: u8)] pub struct Initialize<'info> { + /// Initialize the state account #[account( init, payer = authority, @@ -176,8 +216,8 @@ pub struct Wrap<'info> { #[derive(Accounts)] pub struct Bridge<'info> { - /// The state account that identifies the mint of the token being transferred through the bridge - /// and is also the token account authority + /// State account specifying the mint of the token being transferred through the bridge + /// and the recipient address on the target chain pub state: Account<'info, State>, /// The wormhole bridge authority. This is the authority that will sign the bridge transaction /// and therefore needs to be a delegate on the token account. @@ -199,31 +239,39 @@ pub struct Bridge<'info> { #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub struct GenericStateInput { + /// Mint of the wrapped USDC token to be bridged over to the target chain pub output_mint: Pubkey, + /// Holding contract on the target chain to receive the bridged tokens pub holding_contract: String, + /// Wormhole ID specifying the target chain pub token_chain_id: String, + /// Authority who can update the data in the state account pub update_authority: Pubkey, } #[account] pub struct State { - output_mint: Pubkey, // The target token mint + /// Mint of the wrapped USDC token to be bridged over to the target chain + output_mint: Pubkey, + /// Holding contract on the target chain to receive the bridged tokens holding_contract: String, + /// Wormhole ID specifying the target chain token_chain_id: String, + /// Authority who can update the data in the state account update_authority: Pubkey, } impl State { - pub const SIZE: usize = 8 + 24 + 24 + 32 + 32; // include 8 bytes for the anchor discriminator pub const STATE_SEED: &'static [u8] = b"state_address"; pub const TOKEN_AUTHORITY_SEED: &'static [u8] = b"token_authority"; pub fn space(holding_contract: String, token_chain_id: String) -> usize { - // find space needed for state account for current config + // Find space needed for state account for current config 4 + holding_contract.len() + 4 + token_chain_id.len() + 4 + 32 + 32 + 8 /* Discriminator */ } pub fn get_token_authority(state_address: &Pubkey) -> (Pubkey, u8) { + // Derive token_authority address from the state account address Pubkey::find_program_address(&[Self::TOKEN_AUTHORITY_SEED, state_address.as_ref()], &id()) } } @@ -231,7 +279,7 @@ impl State { #[derive(Accounts)] #[instruction(state_in: GenericStateInput)] pub struct UpdateState<'info> { - // to be used for updating parameters of state account + // To be used for updating parameters of state account #[account(mut)] pub payer: Signer<'info>, #[account( @@ -243,12 +291,16 @@ pub struct UpdateState<'info> { } #[derive(AnchorDeserialize, AnchorSerialize)] -/// Token Bridge instructions. +/// Schema for deserialising the bridge data from Wormhole pub struct TransferWrapped { batch_id: u32, + /// Amount to bridge amount: u64, fee: u64, + /// Wormhole adds zeros in front of the recipient address to accommodate for different address lengths zeros_padding: [u8; 13], + /// Recipient address on target chain recipient_address: [u8; 20], + /// Wormhole ID for target chain recipient_chain: u16, } diff --git a/solana-contract/programs/swap-bridge/src/util/bridge.rs b/solana-contract/programs/swap-bridge/src/util/bridge.rs index 1e4b0cc..c18d4b4 100644 --- a/solana-contract/programs/swap-bridge/src/util/bridge.rs +++ b/solana-contract/programs/swap-bridge/src/util/bridge.rs @@ -23,6 +23,16 @@ pub fn call_bridge<'a>( wormhole_program: &Program<'a, Wormhole>, signer_seeds: &[&[u8]], ) -> Result<()> { + /* To call and bridge funds to target chain + + Parameters + ---------- + bridge_data: data for bridging instructions from Wormhole + accounts: accounts involved in the bridging instructions + token_account_authority: the token authority (also the input account PDA) + wormhole_program: the Wormhole program to carry out the bridging action + signer_seeds: seeds of signers (i.e. the token authority) + */ let mut router_accounts = vec![]; for account in accounts { // transaction signers are: diff --git a/solana-contract/programs/swap-bridge/src/util/token.rs b/solana-contract/programs/swap-bridge/src/util/token.rs index 47bd49c..f9b76d4 100644 --- a/solana-contract/programs/swap-bridge/src/util/token.rs +++ b/solana-contract/programs/swap-bridge/src/util/token.rs @@ -10,6 +10,17 @@ pub fn approve_delegate<'a>( token_program: &Program<'a, Token>, signer_seeds: &[&[u8]], ) -> Result<()> { + /* To approve the bridge (Wormhole) as a delagate of an amount of funds in the token_account + + Parameters + ---------- + amount: amount of funds to delegate to Wormhole + token_account: address of the account which contains the funds to delegate + token_account_owner: owner of the token_account (i.e. the token authority) + delegate: account to which the funds woule be delegated (Wormholde bridge authority) + token_program: Token Program for carrying out CPI transfer + signer_seeds: seeds of signers (i.e. the token authority) + */ msg!("Approving delegate for {}", amount); let seeds = [signer_seeds]; let cpi_accounts = Approve {