Skip to content

Commit

Permalink
Merge pull request #12 from allbridge-io/feature/cctp-solana
Browse files Browse the repository at this point in the history
Added CCTP recipient wallet address for Solana
  • Loading branch information
ysavchenko authored Mar 22, 2024
2 parents 1616b31 + 6ccad9a commit a834f3b
Show file tree
Hide file tree
Showing 8 changed files with 404 additions and 135 deletions.
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,28 @@ Config:
- Set messenger gas usage (check args): `npx hardhat run ./scripts/messenger/set-gas-usage.ts --network goerli`
- Set wormhole gas usage (check args): `npx hardhat run ./scripts/wormhole/set-gas-usage.ts --network goerli`

### Tron (shasta)
### Tron (nile)

- Add to env file `NODE_URL`, `PRIVATE_KEY`, `VALIDATOR_ADDRESS`, `CHAIN_ID`

Deploy:

- Gas oracle: `tronbox migrate --f 1 --to 1 --network shasta` set `GAS_ORACLE_ADDRESS`
- Messenger: `tronbox migrate --f 2 --to 2 --network shasta` set `MESSENGER_ADDRESS`
- Bridge: `tronbox migrate --f 3 --to 3 --network shasta` set `BRIDGE_ADDRESS`
- Optional deploy test token, check args inside : `tronbox migrate --f 4 --to 4 --network shasta`
- Gas oracle: `tronbox migrate --f 1 --to 1 --network nile` set `GAS_ORACLE_ADDRESS`
- Messenger: `tronbox migrate --f 2 --to 2 --network nile` set `MESSENGER_ADDRESS`
- Bridge: `tronbox migrate --f 3 --to 3 --network nile` set `BRIDGE_ADDRESS`
- Optional deploy test token, check args inside : `tronbox migrate --f 4 --to 4 --network nile`
set `TOKEN_ADDRESS`
- Pool: `tronbox migrate --f 5 --to 5 --network shasta` set `POOL_ADDRESS`
- Pool: `tronbox migrate --f 5 --to 5 --network nile` set `POOL_ADDRESS`

Config:

- Approve token `node ./scripts/tron/approve-token.js --network shasta`
- Add pool liquidity (check amount): `node ./scripts/tron/add-pool-liquidity.js --network shasta`
- Add pool to the bridge: `node ./scripts/tron/add-pool.js --network shasta`
- Set bridge (check args): `node ./scripts/tron/add-bridge.js --network shasta`
- Add bridge token (check args): `node ./scripts/tron/add-bridge-token.js --network shasta`
- Set bridge gas usage (check args): `node ./scripts/tron/set-bridge-gas-usage.js --network shasta`
- Set messenger gas usage (check args): `node ./scripts/tron/set-messenger-gas-usage.js --network shasta`
- Approve token `node ./scripts/tron/approve-token.js --network nile`
- Add pool liquidity (check amount): `node ./scripts/tron/add-pool-liquidity.js --network nile`
- Add pool to the bridge: `node ./scripts/tron/add-pool.js --network nile`
- Set bridge (check args): `node ./scripts/tron/add-bridge.js --network nile`
- Add bridge token (check args): `node ./scripts/tron/add-bridge-token.js --network nile`
- Set bridge gas usage (check args): `node ./scripts/tron/set-bridge-gas-usage.js --network nile`
- Set messenger gas usage (check args): `node ./scripts/tron/set-messenger-gas-usage.js --network nile`

### CCTP

Expand Down
61 changes: 57 additions & 4 deletions contracts/CctpBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ contract CctpBridge is GasUsage {
uint private immutable fromGasOracleScalingFactor;

mapping(uint chainId => uint domainNumber) private chainIdDomainMap;
mapping(uint nonce => address sender) private senders;

/**
* @notice Emitted when the contract receives some gas directly.
Expand All @@ -51,9 +52,12 @@ contract CctpBridge is GasUsage {
uint receivedRelayerFeeFromTokens,
uint relayerFee,
uint receivedRelayerFeeTokenAmount,
uint adminFeeTokenAmount
uint adminFeeTokenAmount,
bytes32 recipientWalletAddress
);

event RecipientReplaced(address sender, uint nonce, bytes32 newRecipient);

constructor(
uint chainId_,
uint chainPrecision_,
Expand Down Expand Up @@ -82,15 +86,17 @@ contract CctpBridge is GasUsage {
* (See the function `getBridgingCostInTokens`).
* @param amount The amount of tokens to send (including `relayerFeeTokenAmount`).
* @param recipient The recipient address.
* @param recipientWalletAddress The recipient wallet address - used to track user for transfers to Solana.
* @param destinationChainId The ID of the destination chain.
* @param relayerFeeTokenAmount The amount of tokens to be deducted from the transferred amount as a bridging fee.
*/
function bridge(
function _bridge(
uint amount,
bytes32 recipient,
bytes32 recipientWalletAddress,
uint destinationChainId,
uint relayerFeeTokenAmount
) external payable {
) internal {
require(amount > relayerFeeTokenAmount, "CCTP: Amount <= relayer fee");
require(recipient != 0, "CCTP: Recipient must be nonzero");
token.safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -108,6 +114,7 @@ contract CctpBridge is GasUsage {
}
uint32 destinationDomain = getDomainByChainId(destinationChainId);
uint64 nonce = cctpMessenger.depositForBurn(amountToSend, destinationDomain, recipient, address(token));
senders[nonce] = tx.origin;

Check warning on line 117 in contracts/CctpBridge.sol

View workflow job for this annotation

GitHub Actions / ⬣ Lint

Avoid to use tx.origin
emit TokensSent(
amountToSend,
msg.sender,
Expand All @@ -118,10 +125,56 @@ contract CctpBridge is GasUsage {
gasFromStables,
relayerFee,
relayerFeeTokenAmount,
adminFee
adminFee,
recipientWalletAddress
);
}

/**
* @notice Public method to replace recipient if it was accidentally incorrectly specified
* @param originalMessage original message bytes (to replace)
* @param originalAttestation original attestation bytes
* @param newRecipient the new mint recipient, which may be the same as the
* original mint recipient, or different.
**/
function changeRecipient(
bytes calldata originalMessage,
bytes calldata originalAttestation,
bytes32 newRecipient
) external {
uint64 nonce = uint64(bytes8(originalMessage[12:20]));
require(senders[nonce] == tx.origin, "CCTP: wrong sender");

Check warning on line 146 in contracts/CctpBridge.sol

View workflow job for this annotation

GitHub Actions / ⬣ Lint

Avoid to use tx.origin
cctpMessenger.replaceDepositForBurn(originalMessage, originalAttestation, bytes32(0), newRecipient);
emit RecipientReplaced(tx.origin, nonce, newRecipient);

Check warning on line 148 in contracts/CctpBridge.sol

View workflow job for this annotation

GitHub Actions / ⬣ Lint

Avoid to use tx.origin
}

/**
* @notice Public method to initiate a bridging process of the token to another blockchain. Used for recipients with the same wallet address
* @dev See full description in the _bridge method
**/
function bridge(
uint amount,
bytes32 recipient,
uint destinationChainId,
uint relayerFeeTokenAmount
) external payable {
_bridge(amount, recipient, recipient, destinationChainId, relayerFeeTokenAmount);
}

/**
* @notice Public method to initiate a bridging process of the token to another blockchain. Used for recipients with different wallet address (Solana)
* @dev See full description in the _bridge method
**/
function bridgeWithWalletAddress(
uint amount,
bytes32 recipient,
bytes32 recipientWalletAddress,
uint destinationChainId,
uint relayerFeeTokenAmount
) external payable {
_bridge(amount, recipient, recipientWalletAddress, destinationChainId, relayerFeeTokenAmount);
}

/**
* @notice Completes the bridging process by sending the tokens on the destination blockchain to the recipient.
* @param recipient The recipient address.
Expand Down
28 changes: 28 additions & 0 deletions contracts/interfaces/cctp/ITokenMessenger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,32 @@ interface ITokenMessenger {
bytes32 mintRecipient,
address burnToken
) external returns (uint64 _nonce);

/**
* @notice Replace a BurnMessage to change the mint recipient and/or
* destination caller. Allows the sender of a previous BurnMessage
* (created by depositForBurn or depositForBurnWithCaller)
* to send a new BurnMessage to replace the original.
* The new BurnMessage will reuse the amount and burn token of the original,
* without requiring a new deposit.
* @dev The new message will reuse the original message's nonce. For a
* given nonce, all replacement message(s) and the original message are
* valid to broadcast on the destination domain, until the first message
* at the nonce confirms, at which point all others are invalidated.
* Note: The msg.sender of the replaced message must be the same as the
* msg.sender of the original message.
* @param originalMessage original message bytes (to replace)
* @param originalAttestation original attestation bytes
* @param newDestinationCaller the new destination caller, which may be the
* same as the original destination caller, a new destination caller, or an empty
* destination caller (bytes32(0), indicating that any destination caller is valid.)
* @param newMintRecipient the new mint recipient, which may be the same as the
* original mint recipient, or different.
*/
function replaceDepositForBurn(
bytes calldata originalMessage,
bytes calldata originalAttestation,
bytes32 newDestinationCaller,
bytes32 newMintRecipient
) external;
}
7 changes: 7 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ const config: HardhatUserConfig = {
solidity: {
version: '0.8.18',
settings: {
viaIR: true,
optimizer: {
enabled: true,
runs: 1000,
details: {
yulDetails: {
optimizerSteps: 'u',
},
},
},
outputSelection: {
'*': {
Expand All @@ -42,6 +48,7 @@ const config: HardhatUserConfig = {
goerli: baseNetwork,
mumbai: baseNetwork,
sepolia: baseNetwork,
holesky: baseNetwork,
bsc: baseNetwork,
arbitrumGoerli: baseNetwork,
},
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
},
"dependencies": {
"@certusone/wormhole-sdk": "^0.5.0",
"@openzeppelin/contracts": "4.8.3",
"@openzeppelin/contracts": "4.9.6",
"@types/big.js": "^6.1.6",
"base32.js": "^0.1.0",
"big.js": "^6.2.1",
"bs58": "^5.0.0",
"tronweb": "^5.1.0",
"web3": "^1.10.3"
"web3": "^1.10.4"
},
"devDependencies": {
"@defi-wonderland/smock": "^2.3.5",
Expand Down
Loading

0 comments on commit a834f3b

Please sign in to comment.