Injective Typescript Bridge Ethereum
Ethereum
Мост Injective Ethereum позволяет цепочке Injective Chain поддерживать бездоверительный двунаправленный токен-мост на цепочке. В этой системе держатели токенов ERC-20 на Ethereum могут мгновенно конвертировать свои токены ERC-20 в монеты Cosmos-native на Injective Chain и наоборот.
Мост Injective Peggy состоит из трех основных компонентов:
Контракт Peggy на Ethereum
Оркестратор Peggo
Модуль Peggy на Injective Chain
Контракт Peggy
Функция контракта Peggy заключается в обеспечении эффективного двунаправленного межцепочечного перевода токенов ERC-20 из Ethereum в Injective Chain. В отличие от других токен-мостов, мост Injective Peggy - это децентрализованный, не требующий опеки мост, управляемый исключительно валидаторами на Injective. Мост защищен системой доказательств ставок Injective Chain, поскольку депозиты и снятия средств осуществляются в соответствии с подтверждениями, сделанными не менее чем двумя третями валидаторов на основе консенсуса ставок.
Оркестратор Peggo
Орхистратор - это внецепочечный ретранслятор, которым управляет каждый валидатор Injective Chain, выполняющий функцию передачи данных о переводе токенов ERC-20 из Ethereum в Injective Chain.
Модуль Peggy
На базовом уровне модуль Peggy майнит новые токены в Injective Chain при пополнении счета ERC-20 из Ethereum и сжигает токены при выводе токена из Injective Chain обратно в Ethereum. Модуль Peggy также управляет экономическими стимулами, обеспечивающими честные и эффективные действия валидаторов, с помощью различных механизмов, включая косые штрафы, вознаграждения за нативные токены и комиссии за вывод средств.
Из Ethereum в Injective
Для перевода из Ethereum в Injective необходимо совершить Web3-транзакцию и взаимодействовать с контрактом Peggy на Ethereum. Для осуществления перевода необходимо выполнить два шага:
Поскольку мы, по сути, фиксируем наши ERC20-активы на контракте Peggy, который живет на Ethereum, нам необходимо установить резерв для активов, которые мы переводим на контракт Peggy. Здесь мы привели пример того, как провести эту транзакцию, и вы можете использовать любого web3-провайдера для подписания и трансляции транзакции в сеть Ethereum.
После того как резерв установлен, необходимо вызвать функцию sendToInjective на контракте Peggy с указанием желаемой суммы и актива, который мы хотим перевести в цепь Injective, пример можно найти здесь. Получив транзакцию, мы можем использовать провайдер web3 для подписания и трансляции транзакции в сеть Ethereum. После подтверждения транзакции потребуется несколько минут, чтобы активы отобразились в Injective Chain.
Несколько замечаний по поводу приведенных примеров:
Адрес назначения (если вы хотите построить транзакцию самостоятельно) имеет следующий формат, где Ethereum-адрес - соответствующий Ethereum-адрес инъективного адреса назначения
"0x000000000000000000000000{ETHEREUM_ADDRESS_HERE_WITHOUT_0X_PREFIX}" // example "0x000000000000000000000000e28b3b32b6c345a34ff64674606124dd5aceca30"
const web3 = walletStrategy.getWeb3() walletStrategy - это созданная нами абстракция, поддерживающая множество кошельков, которые можно использовать для подписания и трансляции транзакций (как на Ethereum, так и на Injective Chain), более подробную информацию можно найти в документации пакета npm @injectivelabs/wallet-ts. Разумеется, это лишь пример, и для обработки транзакций можно использовать как непосредственно пакет web3, так и любой другой провайдер web3.
import { PeggyContract } from '@injectivelabs/contracts'
const contract = new PeggyContract({ ethereumChainId, address: peggyContractAddress, web3: web3 as any, })
Приведенный ниже фрагмент инстанцирует экземпляр PeggyContract, который может легко оценитьGas и отправитьTransaction, используя web3, который мы предоставляем конструктору контракта. Его реализацию можно найти здесь. Очевидно, что это лишь пример, и вы можете использовать пакет web3 напрямую + ABI контракта для инстанцирования контракта, а затем обработать логику подписания и трансляции транзакции с помощью какого-либо web3-провайдера.
Из Injective в Ethereum
Теперь, когда ERC20-версия INJ переведена в Injective, на цепочке Injective майнится собственный дензнак inj, который является канонической версией токена INJ. Для вывода inj из Injective в Ethereum нам необходимо подготовить, подписать и затем транслировать нативную транзакцию Cosmos на цепочке Injective.
Если вы не знакомы с тем, как работают транзакции (и сообщения) в Cosmos, вы можете найти дополнительную информацию здесь. Сообщение, которое мы должны упаковать в транзакцию, чтобы дать команду Injective вывести средства из Injective в Ethereum, - это MsgSendToEth.
При вызове MsgSendToEth в цепочке некоторые валидаторы подхватят транзакцию, объединят несколько запросов MsgSendToEth в один и: сожгут выводимые активы на Injective, разблокируют эти средства на смарт-контракте Peggy на Ethereum и отправят их на соответствующий адрес.
Для того чтобы стимулировать валидаторов быстрее принимать и обрабатывать ваши заявки на вывод средств, в эти транзакции включается бридж-пеня. BridgeFee находится в активе, который пользователь хочет вывести в Ethereum (если вы выводите INJ, то должны заплатить bridgeFee также в INJ).
Вот пример реализации, которая подготавливает транзакцию, использует privateKey для ее подписи и, наконец, транслирует ее в Injective:
import { getNetworkInfo, Network } from "@injectivelabs/networks"; import { TxClient, PrivateKey, TxRestClient, MsgSendToEth, DEFAULT_STD_FEE, ChainRestAuthApi, createTransaction } from "@injectivelabs/sdk-ts"; import { BigNumberInBase } from "@injectivelabs/utils";
/** MsgSendToEth Example */ (async () => { const network = getNetworkInfo(Network.Mainnet); // Gets the rpc/lcd endpoints const privateKeyHash = "f9db9bf330e23cb7839039e944adef6e9df447b90b503d5b4464c90bea9022f3"; const privateKey = PrivateKey.fromPrivateKey(privateKeyHash); const injectiveAddress = privateKey.toBech32(); const ethAddress = privateKey.toHex(); const publicKey = privateKey.toPublicKey().toBase64();
/** Account Details **/ const accountDetails = await new ChainRestAuthApi( network.sentryHttpApi ).fetchAccount(injectiveAddress);
/** Prepare the Message */ const amount = { amount: new BigNumberInBase(0.01).toWei().toFixed(), denom: "inj", }; const bridgeAmount = { amount: new BigNumberInBase(0.01).toWei().toFixed(), denom: "inj", };
const msg = MsgSendToEth.fromJSON({ amount, bridgeFee, injectiveAddress, address: ethAddress, })
/** Prepare the Transaction **/ const { signBytes, txRaw } = createTransaction({ message: msg, fee: DEFAULT_STD_FEE, pubKey: publicKey, sequence: parseInt(accountDetails.account.base_account.sequence, 10), accountNumber: parseInt( accountDetails.account.base_account.account_number, 10 ), chainId: network.chainId, });
/** Sign transaction */ const signature = await privateKey.sign(Buffer.from(signBytes));
/** Append Signatures */ txRaw.signatures = [signature];
/** Calculate hash of the transaction */ console.log(`Transaction Hash: ${TxClient.hash(txRaw)}`);
const txService = new TxRestClient(network.sentryHttpApi);
/** Simulate transaction */ const simulationResponse = await txService.simulate(txRaw); console.log( `Transaction simulation response: ${JSON.stringify( simulationResponse.gasInfo )}` );
/** Broadcast transaction */ const txResponse = await txService.broadcast(txRaw);
if (txResponse.code !== 0) { console.log(`Transaction failed: ${txResponse.rawLog}`); } else { console.log( `Broadcasted transaction hash: ${JSON.stringify(txResponse.txhash)}` ); } })();