securewalletbundle
Version:
Un wallet 100% sécurisé, sécurisé par vous. Pour XRP et XLM pour l'instant. Vous pouvez télécharger et vérifier/valider le code grâce à ce package.
674 lines (662 loc) • 28.2 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml" lang="en_US">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="author" content="Decrypto"/>
<meta name="description" content="Envoyer une transation - ONLINE"/>
<meta name="version" content="2.0"/>
<title>2.3 - ONLINE - Send Transaction</title>
<!-- ////////////////////////////////////////////////////// LIBS PART ////////////////////////////////////////////////////// -->
<!-- UI BOOTSTRAP CSS LIBS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<!-- JQUERY LIBS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- SCRIPT FOR XRP & XLM BLOCKCHAIN -->
<script src="https://unpkg.com/securewalletbundle@2.5.3/dist/SecureWalletBundle.browser.min.js" integrity="sha256-2ZubSXQsoaoPU0YsTc6BkLBXVfEHjBysA4v/e+HDwHw=" crossorigin="anonymous"></script>
<!-- //////////////////////////////////////////////////// END LIBS PART //////////////////////////////////////////////////// -->
<!-- BLOCKCHAIN NETWORK MANAGEMENT -->
<script>
const {xrpl,xrplCodec,StellarSdk} = SecureWalletBundle;
const CLASSES = {
//------------------------------------- XRPL -------------------------------------------
"XRPL":class XRPL {
static serverURL = { "main":"wss://xrplcluster.com", "test":"wss://s.altnet.rippletest.net:51233"};
static isLibLoaded(){
return !(typeof xrpl === "undefined");
}
static curMaxLen = 6;
symbol = "XRP";
constructor(mt) {
this.main = (mt || false) && mt=="main";
this.client = new xrpl.Client(XRPL.serverURL[this.main?"main":"test"]);
}
isMain(){
return this.main;
}
async connect(){
if (this.isConnected !== true){
await this.client.connect();
this.isConnected = true;
}
}
switchServer(mt){
if (!mt){
mt = this.main?"test":"main";
}
mt = mt=="main";
if (this.main && !mt){//we are main, we go test
if (this.isConnected === true){
this.isConnected = false;
try { this.client.disconnect(); } catch(err){}
}
this.client = new xrpl.Client(XRPL.serverURL["test"]);
this.main = false;
} else if (!this.main && mt){//we are test, we go main
if (this.isConnected === true){
this.isConnected = false;
try { this.client.disconnect(); } catch(err){}
}
this.client = new xrpl.Client(XRPL.serverURL["main"]);
this.main = true;
}
}
#cur40ToCur(text){
if (text.length < XRPL.curMaxLen){ return text; }
return text.match(/.{1,2}/g).map(function(v){
return String.fromCharCode(parseInt(v, 16));
}).join('').replace(/\0/g, '').toUpperCase();
}
decode(trx){
var rawTrx = xrplCodec.decode(trx.tx_blob);
switch(rawTrx.TransactionType){
case "Payment":
return {
type : "Payment",
trx : {
from : rawTrx.Account,
to : rawTrx.Destination,
currency : rawTrx.Amount.currency?this.#cur40ToCur(rawTrx.Amount.currency):this.symbol,
amount : rawTrx.Amount.value?rawTrx.Amount.value:xrpl.dropsToXrp(rawTrx.Amount),
fee : xrpl.dropsToXrp(rawTrx.Fee),
tag : rawTrx.DestinationTag,
multisign : rawTrx.SigningPubKey == ""
}
};
case "TrustSet":
return {
type : rawTrx.LimitAmount.value==0?"TrustRev":"TrustSet",
trx : {
from : rawTrx.Account,
issuer : rawTrx.LimitAmount.issuer,
currency : this.#cur40ToCur(rawTrx.LimitAmount.currency),
max : rawTrx.LimitAmount.value,
fee : xrpl.dropsToXrp(rawTrx.Fee),
multisign : rawTrx.SigningPubKey == ""
}
};
case "AccountDelete":
return {
type : "AccountDelete",
trx : {
from : rawTrx.Account,
to : rawTrx.Destination,
fee : xrpl.dropsToXrp(rawTrx.Fee),
tag : rawTrx.DestinationTag,
multisign : rawTrx.SigningPubKey == ""
}
};
case "SignerListSet":
return {
type : rawTrx.SignerQuorum==0?"SignerListDel":"SignerListSet",
trx : {
from : rawTrx.Account,
signer : rawTrx.SignerEntries?rawTrx.SignerEntries[0].SignerEntry.Account:false,
fee : xrpl.dropsToXrp(rawTrx.Fee),
multisign : rawTrx.SigningPubKey == ""
}
};
case "AccountSet":
var flag = rawTrx.SetFlag || rawTrx.ClearFlag || false;
if (flag === false || flag != xrpl.AccountSetAsfFlags.asfDisableMaster){
return {
type:"unknown",
trx : rawTrx,
multisign : rawTrx.SigningPubKey == ""
};
}
return {
type : rawTrx.SetFlag?"MasterOff":"MasterOn",
trx : {
from : rawTrx.Account,
fee : xrpl.dropsToXrp(rawTrx.Fee),
multisign : rawTrx.SigningPubKey == ""
}
};
default:
return {
type:"unknown",
trx : rawTrx,
multisign : rawTrx.SigningPubKey == ""
};
}
}
async send(tx){
if (!tx.tx_blob) throw "Cette transaction n'est pas une transaction XRPL !";
this.lastSendSuccess = false;
this.lastTrxHash = tx.hash;
var resp = await this.client.submitAndWait(tx.tx_blob);
this.lastSendSuccess = (resp.result.meta.TransactionResult == "tesSUCCESS") || resp.result.meta.TransactionResult || false;
return resp;
}
getLastSendSuccess(){
return this.lastSendSuccess;
}
buildTrxLink(){
return (this.main?'https://xrpscan.com/tx/':'https://testnet.xrpl.org/transactions/')+this.lastTrxHash;
}
tryReadError(err){
return err.toString();
}
isSuchTransaction(trx){
return trx.tx_blob && trx.hash ? true : false;
}
},
//------------------------------------- XLM -------------------------------------------
"XLM":class XLM {
static serverURL = { "main":"https://horizon.stellar.org", "test":"https://horizon-testnet.stellar.org"};
static isLibLoaded(){
return !(typeof StellarSdk === "undefined");
}
symbol = "XLM";
constructor(mt) {
this.main = (mt || false) && mt=="main";
this.server = new StellarSdk.Horizon.Server(XLM.serverURL[this.main?"main":"test"]);
}
isMain(){
return this.main;
}
async connect(){
this.isConnected = true;
}
switchServer(mt){
if (!mt){
mt = this.main?"test":"main";
}
mt = mt=="main";
if (this.main && !mt){//we are main, we go test
this.server = new StellarSdk.Horizon.Server(XLM.serverURL["test"]);
this.main = false;
} else if (!this.main && mt){//we are test, we go main
this.server = new StellarSdk.Horizon.Server(XLM.serverURL["main"]);
this.main = true;
}
}
decode(trx){
var rawTrx = StellarSdk.TransactionBuilder.fromXDR(trx.XDR,trx.Network);
switch(rawTrx._operations[0].type){
case "createAccount":
case "payment":
return {
type : "Payment",
trx : {
from : rawTrx._source,
to : rawTrx._operations[0].destination,
currency : rawTrx._operations[0].type=="createAccount"?this.symbol:rawTrx._operations[0].asset.code,
amount : rawTrx._operations[0].type=="createAccount"?rawTrx._operations[0].startingBalance.replace(/\.?0+$/,''):rawTrx._operations[0].amount.replace(/\.?0+$/,''),
fee : (rawTrx._fee/Math.pow(10,7)).toFixed(7).replace(/0+$/,''),
tag : rawTrx._memo._value?(new TextDecoder().decode(rawTrx._memo._value)):rawTrx._memo._value
}
}
case "changeTrust":
return {
type : rawTrx._operations[0].limit==0?"TrustRev":"TrustSet",
trx : {
from : rawTrx._source,
issuer : rawTrx._operations[0].line.issuer,
currency : rawTrx._operations[0].line.code,
max : rawTrx._operations[0].limit.replace(/\.?0+$/,''),
fee : (rawTrx._fee/Math.pow(10,7)).toFixed(7).replace(/0+$/,''),
}
};
case "accountMerge":
return {
type : "AccountDelete",
trx : {
from : rawTrx._source,
to : rawTrx._operations[0].destination,
fee : (rawTrx._fee/Math.pow(10,7)).toFixed(7).replace(/0+$/,''),
tag : rawTrx._memo._value?(new TextDecoder().decode(rawTrx._memo._value)):rawTrx._memo._value,
}
};
case "setOptions":
if (rawTrx._operations[0].signer || rawTrx._operations[0].masterWeight >= 0){
var signer = rawTrx._operations[0].signer;
var onMaster = rawTrx._operations[0].masterWeight >= 0;
var signSet = onMaster?rawTrx._operations[0].masterWeight>0:signer.weight > 0;
return {
type : onMaster?(signSet?"MasterOn":"MasterOff"):(signSet?"SignerListSet":"SignerListDel"),
trx : {
from : rawTrx._source,
signer : onMaster?false:signer.ed25519PublicKey,
fee : (rawTrx._fee/Math.pow(10,7)).toFixed(7).replace(/0+$/,''),
multisign : false
}
};
} else {
return {
type:"unknown",
trx : rawTrx,
multisign : false
};
}
default:
return {
type:"unknown",
trx : rawTrx,
multisign : false
};
}
}
async send(tx){
if (!tx.XDR) throw "Cette transaction n'est pas une transaction XLM !";
this.lastSendSuccess = false;
var transaction = StellarSdk.TransactionBuilder.fromXDR(tx.XDR,tx.Network);
var transactionResult = await this.server.submitTransaction(transaction);
this.lastTrxHash = transactionResult.id;
this.lastSendSuccess = true;
return transactionResult;
}
getLastSendSuccess(){
return this.lastSendSuccess;
}
buildTrxLink(){
return (this.main?'https://lumenscan.io/txns/':'https://testnet.lumenscan.io/txns/')+this.lastTrxHash;
}
tryReadError(err){
if (err.response && err.response.data && err.response.data.extras && err.response.data.extras.result_codes && err.response.data.extras.result_codes){
return err.toString()+" - Reason : <br/>"+JSON.stringify(err.response.data.extras.result_codes,null, 3);
} else {
return err.toString();
}
}
isSuchTransaction(trx){
return trx.XDR && trx.Network ? true : false;
}
}
};
var NETWORK;
$(document).on('NETWORK_CHANGED', (e,n,s) => {
var _class_ = CLASSES[n];
if (_class_.isLibLoaded()){
NETWORK = new _class_(s);
$('#libCompromised').hide();
$('#bg-cur span.cur').text(NETWORK.symbol);
$('.container').show();
} else {
$('#libCompromised span').text(n);
$('#libCompromised').show();
$('.container').hide();
}
});
</script>
<!-- MAIN -->
<style type="text/css">
input[type="file"] {
width:400px;
}
pre {
border:1px #AAA solid;
border-radius:10px;
padding:10px;
}
li.list-group-item {
padding:5px;
}
.checkAlert {
font-size:120%;
}
.checkAlert .badge {
font-family:system-ui,-apple-system,"Segoe UI",Roboto;
}
.checkAlert .badge.text-bg-secondary{
letter-spacing:1px;
}
pre {
background-color:#fff9;
}
</style>
<script>
const _online_ = {};
function highlightAddr(addr){
return '<b>'+addr.substr(0,4)+'</b><span style="color:#bbb;">'+addr.substr(4,addr.length-8)+'</span><b>'+addr.substr(addr.length - 4)+'</b>';
}
function stringify(jsObj){
return JSON.stringify(jsObj, null, 3).replace(/\n/g, "<br/>").replace(/ /g, " ");
}
$(function(){
$('input[type="radio"][name="ServerRadio"]').change(function() {
NETWORK.switchServer(this.value);
if (this.value === "main"){
$('#bg-cur').removeClass('bg-danger').addClass('bg-success');
} else {
$('#bg-cur').removeClass('bg-success').addClass('bg-danger');
}
});
$('input[type="radio"][name="ServerRadio"]:checked').trigger("change");
$('#trxSignedInputFile').on('change', (event) => {
var file = event.target.files[0];
if (file) {
if (file.type === 'application/json') {
var reader = new FileReader();
reader.onload = (e) => {
$('#trxSigned').val(e.target.result);
$('#sendTrxBtn').removeAttr('disabled');
event.target.value = null;//chrome does not call onChange when filename is same, so reset it
//change network if needed
var matches = file.name.match(/\-[^\.\-]+/g);
if (matches.length >= 1){
$('#network'+matches[0].toLowerCase()).trigger('click', true);
}
//change server (main/test)
if (matches.length >= 2){
$('#server'+matches[1].toLowerCase()).trigger("click");
}
_online_.check(e.target.result);
};
reader.readAsText(file);
} else {
alert('Veuillez sélectionner un fichier texte json (.signed.json)');
}
}
});
$('#trxSigned').on('input', (event) => {
$('#sendTrxBtn').removeAttr('disabled');
_online_.check($('#trxSigned').val());
});
if (window.navigator && !window.navigator.onLine){
$('#nav-state-offline').show();
}
});
_online_.getTrx = function(signedTrx){
var textArea = $('#trxSigned');
textArea.removeClass("is-invalid");
var tx = textArea.val().trim();
$('.invalid-feedback',textArea.parent()).hide();
if (tx.length == 0){
textArea.addClass("is-invalid");
$('.invalid-feedback',textArea.parent()).text("Veuillez charger un fichier ou copier une transaction signée d'abord !").show();
return;
}
try {
tx = JSON.parse(tx);
} catch (error){
console.error(error);
textArea.addClass("is-invalid");
$('.invalid-feedback',textArea.parent()).html("Ce contenu n'est pas un objet JSON valid : <b>"+error.toString()+"</b>").show();
return;
}
return tx;
}
_online_.check = function(signedTrx){
var tx = _online_.getTrx();
var decoded = NETWORK.decode(tx);
var htmlCheck;
switch(decoded.type){
case "Payment" :
htmlCheck = '<div class="checkAlert alert alert-primary" role="alert">'+
'<b><u>Transfert:</u></b><br>'+
'De : <span class="badge text-bg-secondary">'+highlightAddr(decoded.trx.from)+'</span><br>'+
'Vers : <span class="badge text-bg-primary">'+highlightAddr(decoded.trx.to)+'</span><br>'+
'Tag : <span class="badge text-bg-success">'+(decoded.trx.tag?decoded.trx.tag:'Aucun tag')+'</span><br>'+
'Montant : <span class="badge text-bg-info">'+decoded.trx.amount+' '+decoded.trx.currency+'</span><br>'+
'Frais : <span class="badge text-bg-warning">'+decoded.trx.fee+' '+NETWORK.symbol+'</span>'+
'</div>';
break;
case "TrustSet" :
case "TrustRev" :
htmlCheck = '<div class="checkAlert alert alert-primary" role="alert">'+
'<b><u>'+(decoded.type=="TrustSet"?"Définition":"Révocation")+' d\'une trustline:</u></b><br>'+
'Compte : <span class="badge text-bg-secondary">'+highlightAddr(decoded.trx.from)+'</span><br>'+
'Issuer : <span class="badge text-bg-primary">'+highlightAddr(decoded.trx.issuer)+'</span><br>'+
'Currency : <span class="badge text-bg-success">'+decoded.trx.currency+'</span><br>'+
(decoded.trx.max==0?'':'Max : <span class="badge text-bg-info">'+decoded.trx.max+'</span><br>')+
'Frais : <span class="badge text-bg-warning">'+decoded.trx.fee+' '+NETWORK.symbol+'</span>'+
'</div>';
break;
case "AccountDelete" :
htmlCheck = '<div class="checkAlert alert alert-primary" role="alert">'+
'<b><u>Suppression de compte:</u></b><br>'+
'Compte : <span class="badge text-bg-secondary">'+highlightAddr(decoded.trx.from)+'</span><br>'+
'Reliquat vers : <span class="badge text-bg-primary">'+highlightAddr(decoded.trx.to)+'</span><br>'+
'Tag : <span class="badge text-bg-success">'+(decoded.trx.tag?decoded.trx.tag:'Aucun tag')+'</span><br>'+
'Frais : <span class="badge text-bg-warning">'+decoded.trx.fee+' '+NETWORK.symbol+'</span>'+
'</div>';
break;
case "SignerListSet" :
htmlCheck = '<div class="checkAlert alert alert-primary" role="alert">'+
'<b><u>Définir signataire:</u></b><br>'+
'Compte : <span class="badge text-bg-secondary">'+highlightAddr(decoded.trx.from)+'</span><br>'+
'Signataire : <span class="badge text-bg-primary">'+highlightAddr(decoded.trx.signer)+'</span><br>'+
'Frais : <span class="badge text-bg-warning">'+decoded.trx.fee+' '+NETWORK.symbol+'</span>'+
'</div>';
break;
case "SignerListDel" :
htmlCheck = '<div class="checkAlert alert alert-primary" role="alert">'+
'<b><u>Supprimer signataire:</u></b><br>'+
'Compte : <span class="badge text-bg-secondary">'+highlightAddr(decoded.trx.from)+'</span><br>'+
(decoded.trx.signer?'Signataire : <span class="badge text-bg-primary">'+highlightAddr(decoded.trx.signer)+'</span><br>':'')+
'Frais : <span class="badge text-bg-warning">'+decoded.trx.fee+' '+NETWORK.symbol+'</span>'+
'</div>';
break;
case "MasterOff" :
case "MasterOn" :
htmlCheck = '<div class="checkAlert alert alert-primary" role="alert">'+
'<b><u>'+(decoded.type=="MasterOff"?"Désactiver":"(Ré)activer")+' clé de compte maître:</u></b><br>'+
'Compte : <span class="badge text-bg-secondary">'+highlightAddr(decoded.trx.from)+'</span><br>'+
'Frais : <span class="badge text-bg-warning">'+decoded.trx.fee+' '+NETWORK.symbol+'</span>'+
'</div>';
break;
default:
htmlCheck = '<div>'+
'<b class="text-danger"> Ce type de transaction ne peut être vérifiée ici, mais voici son code pour validation manuelle :</b><br/>'+
'<pre class="mt-3"><code>'+stringify(decoded.trx)+'</code></pre>'+
'</div>';
}
var $htmlCheck = $(htmlCheck);
if (decoded.trx.multisign){
$htmlCheck.append($('<div><i style="font-size:80%" class="text-secondary">Note : Cette transaction a été signée par un compte signataire et non par le compte maître.</i></div>'));
}
$('#d_checkTrx').html($htmlCheck.get(0).outerHTML);
$('#r_checkTrx').show();
$('#r_send').show();
};
_online_.send = async function(){
$('#d_sending').hide();
$('#trx_OOT').hide();
var tx = _online_.getTrx();
var trx_OOT,trx_OOT_OUT;
try {
$('#d_sending').show();
trx_OOT = setTimeout(function(){$('#trx_OOT').show();}, 8000);
trx_OOT_OUT = setTimeout(function(){
$('#trxFail').html("<b>Erreur:</b> <i>La clé privée qui signe la transaction n'est probablement pas la bonne.</i>");
$('#d_trxKO').show();
$('#sendTrxBtn').removeAttr('disabled');
$('#d_sending').hide();
}, 30000);
var dh = document.body.scrollHeight;
window.scrollTo(0, dh);
$('#d_trxOK').hide();
$('#d_trxKO').hide();
$('#sendTrxBtn').attr('disabled','true');
await NETWORK.connect();
var resp = await NETWORK.send(tx);
$('#trxResult').html(stringify(resp));
$('#trxDetailsLink').attr('href',NETWORK.buildTrxLink());
$('#d_trxOK').show();
if (NETWORK.getLastSendSuccess() === true) {
$('#okbut').hide();
$('#trxResult').removeClass("text-warning").addClass("text-success");
} else {
$('#okbut b').text(NETWORK.getLastSendSuccess());
$('#okbut').show();
$('#trxResult').removeClass("text-success").addClass("text-warning");
}
} catch (error){
error = NETWORK.tryReadError(error);
console.error(error);
$('#trxFail').html(error+"<br/><i>(Voir les logs pour plus de détails)</i>");
$('#d_trxKO').show();
$('#sendTrxBtn').removeAttr('disabled');
} finally {
$('#d_sending').hide();
clearTimeout(trx_OOT);
clearTimeout(trx_OOT_OUT);
window.scrollTo(0, dh+50);
}
};
</script>
</head>
<body class="pb-5">
<div class="text-danger fw-bold text-center mt-3" style="display:none;" id="libCompromised">
ATTENTION DANGER !<br/>
La librarie du <span>...</span> n'a pas pu être chargée <b>ou est compromise et a été altérée sur le CDN</b>, veuillez ne pas utiliser cette librarie.<br/>
Le hash d'integrité peut ne pas correspondre. (Voir les logs pour plus de détails)
</div>
<div class="container">
<div class="px-4 py-3 my-3 text-center">
<h2 class="display-6 fw-bold">Envoi d'une transaction 3/3<br/><b class="text-success">(Envoi sur la blockchain - ONLINE)</b></h2>
<div class="col-lg-8 mx-auto">
<div style="display:none;" class="text-danger" id="nav-state-offline">
<span class="badge text-bg-danger">Vous êtes OFFLINE !</span> Vous devez être connecté à internet pour cette étape.<br/>
<i>Rétablissez la connexion internet et rechargez la page.</i><br/>
<button class="btn btn-danger mt-3" onclick="window.location.reload();">Recharger la page</button>
</div>
<p class="lead mb-4">
Cette étape vous permet d'envoyer une transaction signée, quelque soit la transaction.
</p>
</div>
</div>
<h4>Chargez le fichier de transaction <u>signée</u> ou collez ici la <u>transaction signée</u></h4>
<div class="mb-3">
<label>C'est le fichier ou le contenu que vous avez préparé dans l'étape 2/3 (fichier 2.2)</label><br/>
<label for="trxSignedInputFile" class="btn btn-secondary mt-1">Charger le fichier .signed.json</label><input style="visibility:hidden;width:1px;" accept=".signed.json" id="trxSignedInputFile" type="file"/>
</div>
<div class="mb-3">
<textarea class="form-control" id="trxSigned" rows="8" style="opacity:0.7;"></textarea>
<div class="invalid-feedback"></div>
</div>
<div class="row" id="r_checkTrx" style="display:none;">
<div class="col-8">
<h4 class="text-primary">Vérifiez une dernière fois votre transaction signée !</h4>
<div id="d_checkTrx" class="mb-4">
...
</div>
</div>
</div>
<div class="row" id="r_send" style="display:none;">
<div class="col-8">
<div class="alert alert-warning" role="alert">
<i><b>Vous êtes maintenant prêt à envoyer la transaction.</b><br/>
Celle-ci va être exécutée sur la blockchain. Êtes-vous sûr ?</i>
</div>
<button type="button" class="btn btn-success" onclick="_online_.send()" id="sendTrxBtn">Oui! Envoyer la transaction</button>
</div>
</div>
<div id="d_sending" class="text-warning mt-3" style="display:none;">
<div class="spinner-border" style="vertical-align: middle;" role="status"></div>
<b>Envoi en cours, veuillez patienter et ne rien toucher...</b><br/>
<span style="font-size:90%;" class="text-secondary" id="trx_OOT">Note : si la transaction tourne dans le vide plus de 30s, c'est qu'elle va échouer.<br/><b>→ Vérifiez que vous avez signé avec la bonne clé et que vous avez bien coché la case signataire si vous êtes dans ce cas.</b></span>
</div>
<div class="row mt-3" id="d_trxOK" style="display:none;">
<div class="col-8">
<span class="text-success">OK ! Votre transaction a réussi.</span> <span class="text-warning" id="okbut" style="display:none;">Mais elle n'a pas pu se terminer correctement sur la blockchain (<b></b>).</span><br/>
<a id="trxDetailsLink" class="link-info link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" target="_blank" href="https://...">Détails de la transaction...</a><br/>
<b><u><a href="javascript:;" onclick="$('#success-details').slideToggle()">Détails du résultat :</a></u></b><br/>
<pre id="success-details" class="mt-3 text-success" style="display:none;"><code id="trxResult"></code></pre>
</div>
</div>
<div class="row mt-3" id="d_trxKO" style="display:none;">
<div class="col-8">
<span class="text-danger">Votre transaction a échoué.</span><br/>
<b><u>Détails du résultat :</u></b><br/>
<pre class="mt-3 text-danger"><code id="trxFail"></code></pre>
</div>
</div>
<ul class="list-group position-absolute m-1" style="width:180px;font-size:90%;right:0;top:0;">
<li class="list-group-item list-group-item-success">
<input class="form-check-input me-1" type="radio" name="ServerRadio" value="main" id="server-main" checked />
<label class="form-check-label" for="server-main">MainNet (En vrai)</label>
</li>
<li class="list-group-item list-group-item-danger">
<input class="form-check-input me-1" type="radio" name="ServerRadio" value="test" id="server-test"/>
<label class="form-check-label" for="server-test">TestNet (Pour tester)</label>
</li>
</ul>
</div><!-- container -->
<div class="fixed-bottom text-end m-1" style="width:120px;right:0;left:auto;"><span class="badge text-bg-info p-2"><a id="tuto-video" href="..." target="_blank">Tutoriel vidéo</a></span></div>
<h4 class="fixed-top m-1" style="width:150px;"><span id="network-selected" class="badge rounded-pill text-bg-dark">...</span>
<div id="networks" style="margin-left:5px;display:none;">
<div>
<input id="network-xrpl-radio" type="radio" name="blockchain" value="XRPL" style="display:none;" checked />
<label for="network-xrpl-radio"><span id="network-xrpl" class="nw-selector badge rounded-pill text-bg-secondary" tuto="https://youtu.be/djt5ZKKJrWI">XRPL</span></label>
</div>
<div>
<input id="network-xlm-radio" type="radio" name="blockchain" value="XLM" style="display:none;" />
<label for="network-xlm-radio"><span id="network-xlm" class="nw-selector badge rounded-pill text-bg-secondary" tuto="https://youtu.be/CJpHtLly6n4">XLM</span></label>
</div>
</div>
</h4>
<div id="bg-cur" class="fixed-top" style="width:100vw;height:100vh;z-index:-1;opacity:0.055;">
<div class="text-center" style="width:100vw;height:100vh;font-size:100vh;line-height:100vh;margin-top:-7vh;letter-spacing:40px;color:#FFF;">
<span class="cur fw-bold">XRP</span>
</div>
</div>
<style>
#network-selected:hover {
cursor:pointer;
opacity:90%;
}
#network-selected::after {
color:#AAA;
display: inline-block;
margin-left: .255em;
vertical-align: .255em;
content: "";
border-top: .3em solid;
border-right: .3em solid transparent;
border-bottom: 0;
border-left: .3em solid transparent;
}
#network-selected:hover::after {
color:#fff;
}
.nw-selector:hover{
cursor:pointer;
opacity:90%;
}
</style>
<script>
var $selectedNW = $('#network-selected');
var $networks = $('#networks');
var lastUsedNetwork = $('input[name="blockchain"]:checked').val();
$selectedNW.on("click", function(){
$networks.toggle();
});
for (var netw of Object.keys(CLASSES)) {
$('#network-'+netw.toLowerCase()).on('click',function(e, force){
var n = $('#'+($(this).attr('id')+'-radio')).val();
$selectedNW.text(n);
$networks.hide();
if (force || lastUsedNetwork != n){
$(document).trigger('NETWORK_CHANGED',[n,$('input[name="ServerRadio"]:checked').val()]);
lastUsedNetwork = n;
}
$('#tuto-video').attr("href",$(this).attr("tuto"));
});
}
$('#network-'+lastUsedNetwork.toLowerCase()).trigger('click', true);
</script>
</body>
</html>