@@ -30,6 +30,8 @@ contract SponsoredOFTSrcPeriphery is Ownable {
3030 /// @notice Source endpoint id
3131 uint32 public immutable SRC_EID;
3232
33+ mapping (uint32 dstEid = > int8 decimalDiff ) public dstEidToDecimalsDiff;
34+
3335 /// @custom:storage-location erc7201:SponsoredOFTSrcPeriphery.main
3436 struct MainStorage {
3537 /// @notice Signer public key to check the signed quote against
@@ -83,6 +85,8 @@ contract SponsoredOFTSrcPeriphery is Ownable {
8385 error NonceAlreadyUsed ();
8486 /// @notice Thrown when provided msg.value is not sufficient to cover OFT bridging fee
8587 error InsufficientNativeFee ();
88+ /// @notice Thrown when array lengths do not match
89+ error ArrayLengthMismatch ();
8690
8791 constructor (address _token , address _oftMessenger , uint32 _srcEid , address _signer ) {
8892 TOKEN = _token;
@@ -161,8 +165,14 @@ contract SponsoredOFTSrcPeriphery is Ownable {
161165 function _buildOftTransfer (
162166 Quote calldata quote
163167 ) internal view returns (SendParam memory , MessagingFee memory , address ) {
168+ uint256 amountDstLD = _applyDecimalDiff (
169+ quote.signedParams.amountLD,
170+ dstEidToDecimalsDiff[quote.signedParams.dstEid]
171+ );
172+
164173 bytes memory composeMsg = ComposeMsgCodec._encode (
165174 quote.signedParams.nonce,
175+ amountDstLD,
166176 quote.signedParams.deadline,
167177 quote.signedParams.maxBpsToSponsor,
168178 quote.unsignedParams.maxUserSlippageBps,
@@ -179,12 +189,14 @@ contract SponsoredOFTSrcPeriphery is Ownable {
179189 .addExecutorLzReceiveOption (uint128 (quote.signedParams.lzReceiveGasLimit), uint128 (0 ))
180190 .addExecutorLzComposeOption (uint16 (0 ), uint128 (quote.signedParams.lzComposeGasLimit), uint128 (0 ));
181191
192+ // Use maxOftFeeBps to calculate minAmountLD based on expected destination amount
193+ uint256 minAmountLD = (amountDstLD * (10000 - quote.signedParams.maxOftFeeBps)) / 10000 ;
194+
182195 SendParam memory sendParam = SendParam (
183196 quote.signedParams.dstEid,
184197 quote.signedParams.destinationHandler,
185- // Only support OFT sends that don't take fees in sent token. Set `minAmountLD = amountLD` to enforce this
186- quote.signedParams.amountLD,
187198 quote.signedParams.amountLD,
199+ minAmountLD,
188200 extraOptions,
189201 composeMsg,
190202 // Only support empty OFT commands
@@ -196,6 +208,21 @@ contract SponsoredOFTSrcPeriphery is Ownable {
196208 return (sendParam, fee, quote.unsignedParams.refundRecipient);
197209 }
198210
211+ /**
212+ * @notice Applies decimal difference to the amount
213+ * @param amount The amount to adjust
214+ * @param diff The decimal difference (positive: multiply, negative: divide)
215+ * @return The adjusted amount
216+ */
217+ function _applyDecimalDiff (uint256 amount , int8 diff ) internal pure returns (uint256 ) {
218+ if (diff > 0 ) {
219+ return amount * (10 ** uint8 (diff));
220+ } else if (diff < 0 ) {
221+ return amount / (10 ** uint8 (- diff));
222+ }
223+ return amount;
224+ }
225+
199226 function _validateQuote (Quote calldata quote , bytes calldata signature ) internal view {
200227 MainStorage storage $ = _getMainStorage ();
201228 if (! QuoteSignLib.isSignatureValid ($.signer, quote.signedParams, signature)) {
@@ -215,4 +242,18 @@ contract SponsoredOFTSrcPeriphery is Ownable {
215242 function setSigner (address _newSigner ) external onlyOwner {
216243 _getMainStorage ().signer = _newSigner;
217244 }
245+
246+ /**
247+ * @notice Sets the decimal difference for destination chains
248+ * @param dstEids Array of destination endpoint IDs
249+ * @param decimalDiffs Array of decimal differences (positive for Src < Dst, negative for Src > Dst)
250+ */
251+ function setDstEidToDecimalsDiff (uint32 [] calldata dstEids , int8 [] calldata decimalDiffs ) external onlyOwner {
252+ if (dstEids.length != decimalDiffs.length ) {
253+ revert ArrayLengthMismatch ();
254+ }
255+ for (uint256 i = 0 ; i < dstEids.length ; ++ i) {
256+ dstEidToDecimalsDiff[dstEids[i]] = decimalDiffs[i];
257+ }
258+ }
218259}
0 commit comments