-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmorlord-bridge-code.js
More file actions
211 lines (170 loc) · 7.32 KB
/
Copy pathmorlord-bridge-code.js
File metadata and controls
211 lines (170 loc) · 7.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Layer 0 Bridge Code for MOR Token - Extracted from morlord.com
// This code allows bridging MOR tokens between Arbitrum One and Base networks
// Bridge function that handles cross-chain transfers using LayerZero
async function ProcessTransfer() {
// Get destination address and validate
var toAddr = $("#txtTransferAddrTo").val();
var maxMOR = $("#lblTransferBalance").attr("data-value") / 1000000000000000000;
var isValidAddress = false;
try {
_eth.web3.utils.toChecksumAddress(toAddr)
isValidAddress = true;
}
catch (err) {
isValidAddress = false;
}
if (toAddr == "" || !isValidAddress) {
toastr.error("Invalid destination address entered.");
return;
}
// Validate and format amount
var a = $("#txtTransferAmt").val().replace(",", "") * 1;
a = isNaN(a) ? 0 : a;
if (a <= 0) {
toastr.error("Invalid MOR amount entered.");
return;
}
if (a > maxMOR) {
toastr.error("Amount entered is greater than balance.");
return;
}
// Convert amount to wei (18 decimals)
var tmpA = (a + "").split(".");
var amt = (tmpA[0] == 0 ? "" : tmpA[0]) + (tmpA.length > 1 ? tmpA[1].padEnd(18, "0") : "000000000000000000");
//-----------------------------------
// Determine source chain and get LayerZero endpoint ID
var id, curr, qs;
id = $("#ddTransferTo").val() * 1; // LayerZero endpoint ID for destination chain
// Select the current chain's token contract
if (chain.name == "Ethereum") {
curr = _eth;
}
if (chain.name == "Arbitrum") {
curr = _arb;
}
if (chain.name == "Base") {
curr = _base;
}
//--------------------------------------
// Prepare payload for LayerZero send
var toAddr = $("#txtTransferAddrTo").val().replace("0x", "");
$("#btnTransfer").prop("disabled", "true");
$("#btnTransfer").html("Submitting Transfer...");
// Payload structure for LayerZero OFT send:
// [destinationEid, receiver, amountLD, minAmountLD, extraData, composeMsg, oftCmd]
var payload = [id, "0x000000000000000000000000" + toAddr, amt, amt, "0x", "0x", "0x"];
console.log(payload);
//--------------------------------------
// Step 1: Quote the fee for the cross-chain transfer
await curr.token.methods.quoteSend(payload, false).call(function (err, res) {
qs = res; // qs contains [nativeFee, lzTokenFee]
console.log(res);
if (err !== null) {
toastr.error(err);
$("#btnTransfer").removeAttr("disabled");
$("#btnTransfer").html("Transfer");
return;
}
});
//--------------------------------------
// Step 2: Execute the send transaction with LayerZero
// The send function burns tokens on source chain and sends message to destination chain
var d = curr.token.methods.send(payload, qs, $("#txtTransferAddrFrom").val()).encodeABI();
ethereum.request({
method: "eth_sendTransaction",
params: [{
from: accounts[0],
to: chain.token, // MOR token contract address on current chain
value: "0x" + (qs[0] * 1).toString(16), // Native fee for LayerZero
data: d
}]
}).then((result) => {
$("#pane-transfer .ldr").show();
$("#secTransfer").hide();
toastr.success("Transfer was successfully submitted. Transfers can take up to 15 minutes.");
WaitForTransfer(result);
}).catch((err) => {
toastr.error("Transfer was rejected.");
$("#btnTransfer").removeAttr("disabled");
$("#btnTransfer").html("Transfer");
});
}
// Wait for transfer transaction to be confirmed
async function WaitForTransfer(txHash) {
$("#pane-transfer .ldr .ldrMsg").html("Processing transfer, please wait...");
var receipt = await web3.eth.getTransactionReceipt(txHash);
if (receipt == null) {
setTimeout(await WaitForTransfer(txHash), 2000);
} else {
if (receipt.status) {
$("#btnTransfer").removeAttr("disabled");
$("#btnTransfer").html("Transfer");
toastr.success("Transfer completed successfully.");
} else {
toastr.error("Transfer failed to complete.");
}
$("#pane-transfer .ldr .ldrMsg").html("Loading Data...");
initialize(true);
}
}
// ============================================================
// CHAIN CONFIGURATION (from chains.js)
// ============================================================
// LayerZero Endpoint IDs (LzId) - used as destination endpoint ID in payload:
// - Ethereum: 30101
// - Arbitrum: 30110
// - Base: 30184
// MOR Token Contract Addresses (OFT contracts):
// - Arbitrum One: 0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86
// - Base: 0x7431ada8a591c955a994a21710752ef9b882b8e3
// - Ethereum: 0xcBB8f1BDA10b9696c57E13BC128Fe674769DCEc0
// Chain IDs:
// - Ethereum: 1
// - Arbitrum One: 42161
// - Base: 8453
// ============================================================
// HOW THE BRIDGE WORKS
// ============================================================
// The bridge uses LayerZero's OFT (Omnichain Fungible Token) standard:
//
// 1. quoteSend(payload, payInLzToken)
// - Gets the fee estimate for cross-chain transfer
// - Returns: [nativeFee, lzTokenFee] - fees required for the transfer
// - nativeFee: Amount of native token (ETH) needed for LayerZero messaging
// - lzTokenFee: Amount of LZ token needed (if payInLzToken is true)
//
// 2. send(payload, fee, refundAddress)
// - Burns tokens on source chain
// - Sends LayerZero message to destination chain via LayerZero endpoint
// - Payload structure: [destinationEid, receiver, amountLD, minAmountLD, extraData, composeMsg, oftCmd]
// - destinationEid: LayerZero endpoint ID of destination chain (30110 for Arbitrum, 30184 for Base)
// - receiver: Address to receive tokens on destination chain (padded to 32 bytes)
// - amountLD: Amount to send in local decimals (wei for 18 decimals)
// - minAmountLD: Minimum amount to receive (for slippage protection)
// - extraData: Additional data (empty "0x")
// - composeMsg: Compose message (empty "0x")
// - oftCmd: OFT command (empty "0x")
//
// 3. Destination chain receives LayerZero message
// - LayerZero endpoint on destination chain receives the message
// - MOR token contract on destination chain mints tokens to recipient
// - Process typically takes 5-15 minutes
// ============================================================
// EXAMPLE USAGE
// ============================================================
// To bridge from Arbitrum to Base:
// 1. User is connected to Arbitrum network (chainId: 42161)
// 2. User calls ProcessTransfer() with:
// - Destination chain: Base (LzId: 30184)
// - Amount: Amount of MOR tokens to bridge
// - Recipient: Address on Base network
// 3. quoteSend() calculates fees
// 4. send() burns tokens on Arbitrum and sends message to Base
// 5. Base chain receives message and mints tokens to recipient
// To bridge from Base to Arbitrum:
// 1. User is connected to Base network (chainId: 8453)
// 2. User calls ProcessTransfer() with:
// - Destination chain: Arbitrum (LzId: 30110)
// - Amount: Amount of MOR tokens to bridge
// - Recipient: Address on Arbitrum network
// 3. Same process as above, but in reverse direction