From 91e02bcdb6ba7ef7c7a22f0f680eb7d3eb99c685 Mon Sep 17 00:00:00 2001 From: alexcss Date: Tue, 12 Nov 2024 15:27:51 +0200 Subject: [PATCH 1/5] Peg in Address Verifier --- docs/01-concepts/rbtc/conversion.md | 6 +- package.json | 2 + .../pegin-address-verifier/crypto/base58.js | 46 ++++++ .../pegin-address-verifier/crypto/bech32.js | 116 ++++++++++++++ .../crypto/constants.js | 29 ++++ .../crypto/p2pkh-p2sha.js | 90 +++++++++++ .../crypto/segwit-addr.js | 142 ++++++++++++++++++ .../pegin-address-verifier/crypto/utils.js | 41 +++++ .../pegin-address-verifier.js | 70 +++++++++ src/components/AddressVerifier/index.js | 55 +++++++ src/theme/MDXComponents.js | 4 +- yarn.lock | 23 +++ 12 files changed, 619 insertions(+), 5 deletions(-) create mode 100644 src/_utils/pegin-address-verifier/crypto/base58.js create mode 100644 src/_utils/pegin-address-verifier/crypto/bech32.js create mode 100644 src/_utils/pegin-address-verifier/crypto/constants.js create mode 100644 src/_utils/pegin-address-verifier/crypto/p2pkh-p2sha.js create mode 100644 src/_utils/pegin-address-verifier/crypto/segwit-addr.js create mode 100644 src/_utils/pegin-address-verifier/crypto/utils.js create mode 100644 src/_utils/pegin-address-verifier/pegin-address-verifier.js create mode 100644 src/components/AddressVerifier/index.js diff --git a/docs/01-concepts/rbtc/conversion.md b/docs/01-concepts/rbtc/conversion.md index 7bbe5098..384cb6ea 100644 --- a/docs/01-concepts/rbtc/conversion.md +++ b/docs/01-concepts/rbtc/conversion.md @@ -33,6 +33,8 @@ Thus, we have `BTC` and `RBTC` on the Mainnets, which correspond to `tBTC` and ` Enter your BTC address below to verify whether it may be used to peg in from BTC to RBTC. + + ## User Guide - [Mainnet Guide](/concepts/rbtc/networks#mainnet-conversion) @@ -47,9 +49,7 @@ You can try the conversion process using either options below; Watch this explainer video on **How to do BTC & R-BTC Conversions using the Rootstock Powpeg**. -
- -
+ ### FAQs diff --git a/package.json b/package.json index fcd2a910..b33aadf6 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,10 @@ "@mendable/search": "^0.0.206", "@splidejs/react-splide": "^0.7.12", "bootstrap": "5.3.3", + "buffer": "^6.0.3", "clsx": "^2.0.0", "docusaurus-plugin-sass": "^0.2.5", + "jssha": "^3.3.1", "prism-react-renderer": "^2.3.0", "react": "^18.0.0", "react-bootstrap": "^2.10.2", diff --git a/src/_utils/pegin-address-verifier/crypto/base58.js b/src/_utils/pegin-address-verifier/crypto/base58.js new file mode 100644 index 00000000..5b59fe0b --- /dev/null +++ b/src/_utils/pegin-address-verifier/crypto/base58.js @@ -0,0 +1,46 @@ +// Base58 encoding/decoding +// Originally written by Mike Hearn for BitcoinJ +// Copyright (c) 2011 Google Inc +// Ported to JavaScript by Stefan Thomas +// Merged Buffer refactorings from base58-native by Stephen Pair +// Copyright (c) 2013 BitPay Inc + +var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; +var ALPHABET_MAP = {}; +for (var i = 0; i < ALPHABET.length; ++i) { + ALPHABET_MAP[ALPHABET.charAt(i)] = i; +} +var BASE = ALPHABET.length; + +module.exports = { + decode: function(string) { + if (string.length === 0) return []; + + var i, j, bytes = [0]; + for (i = 0; i < string.length; ++i) { + var c = string[i]; + if (!(c in ALPHABET_MAP)) throw new Error('Non-base58 character'); + + for (j = 0; j < bytes.length; ++j) bytes[j] *= BASE + bytes[0] += ALPHABET_MAP[c]; + + var carry = 0; + for (j = 0; j < bytes.length; ++j) { + bytes[j] += carry; + carry = bytes[j] >> 8; + bytes[j] &= 0xff + } + + while (carry) { + bytes.push(carry & 0xff); + carry >>= 8; + } + } + // deal with leading zeros + for (i = 0; string[i] === '1' && i < string.length - 1; ++i){ + bytes.push(0); + } + + return bytes.reverse(); + } +}; diff --git a/src/_utils/pegin-address-verifier/crypto/bech32.js b/src/_utils/pegin-address-verifier/crypto/bech32.js new file mode 100644 index 00000000..effe8002 --- /dev/null +++ b/src/_utils/pegin-address-verifier/crypto/bech32.js @@ -0,0 +1,116 @@ +// Copyright (c) 2017 Pieter Wuille +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; +var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; + +module.exports = { + decode: decode, + encode: encode, +}; + + +function polymod (values) { + var chk = 1; + for (var p = 0; p < values.length; ++p) { + var top = chk >> 25; + chk = (chk & 0x1ffffff) << 5 ^ values[p]; + for (var i = 0; i < 5; ++i) { + if ((top >> i) & 1) { + chk ^= GENERATOR[i]; + } + } + } + return chk; +} + +function hrpExpand (hrp) { + var ret = []; + var p; + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) >> 5); + } + ret.push(0); + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) & 31); + } + return ret; +} + +function verifyChecksum (hrp, data) { + return polymod(hrpExpand(hrp).concat(data)) === 1; +} + +function createChecksum (hrp, data) { + var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); + var mod = polymod(values) ^ 1; + var ret = []; + for (var p = 0; p < 6; ++p) { + ret.push((mod >> 5 * (5 - p)) & 31); + } + return ret; +} + +function encode (hrp, data) { + var combined = data.concat(createChecksum(hrp, data)); + var ret = hrp + '1'; + for (var p = 0; p < combined.length; ++p) { + ret += CHARSET.charAt(combined[p]); + } + return ret; +} + +function decode (bechString) { + var p; + var has_lower = false; + var has_upper = false; + for (p = 0; p < bechString.length; ++p) { + if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { + return null; + } + if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { + has_lower = true; + } + if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { + has_upper = true; + } + } + if (has_lower && has_upper) { + return null; + } + bechString = bechString.toLowerCase(); + var pos = bechString.lastIndexOf('1'); + if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { + return null; + } + var hrp = bechString.substring(0, pos); + var data = []; + for (p = pos + 1; p < bechString.length; ++p) { + var d = CHARSET.indexOf(bechString.charAt(p)); + if (d === -1) { + return null; + } + data.push(d); + } + if (!verifyChecksum(hrp, data)) { + return null; + } + return {hrp: hrp, data: data.slice(0, data.length - 6)}; +} diff --git a/src/_utils/pegin-address-verifier/crypto/constants.js b/src/_utils/pegin-address-verifier/crypto/constants.js new file mode 100644 index 00000000..7e69711b --- /dev/null +++ b/src/_utils/pegin-address-verifier/crypto/constants.js @@ -0,0 +1,29 @@ +const ADDRESS_TYPES = { + P2PKH: 'p2pkh', + P2SH: 'p2sh', + BECH32: 'bech32' +}; + +const NETWORKS = { + MAINNET: 'mainnet', + TESTNET: 'testnet', + REGTEST: 'regtest' +}; + +const HASH_FIELD_NAMES = { + p2pkh: 'scriptPubKey', + p2sh: 'scriptHash' +}; + +// Check https://github.com/rsksmart/RSKIPs/blob/2c994cc108885ccc5a116e4aee8c073b5eca5682/IPs/RSKIP170.md#specification for more details. +const ADDRESS_TYPES_CODES = { + p2pkh: '01', + p2sh: '02' +}; + +module.exports = { + ADDRESS_TYPES, + NETWORKS, + HASH_FIELD_NAMES, + ADDRESS_TYPES_CODES, +}; diff --git a/src/_utils/pegin-address-verifier/crypto/p2pkh-p2sha.js b/src/_utils/pegin-address-verifier/crypto/p2pkh-p2sha.js new file mode 100644 index 00000000..1682525e --- /dev/null +++ b/src/_utils/pegin-address-verifier/crypto/p2pkh-p2sha.js @@ -0,0 +1,90 @@ +let base58 = require('./base58') +let { Buffer } = require('buffer') +let { toHex, sha256Checksum } = require('./utils') +let { ADDRESS_TYPES, NETWORKS, HASH_FIELD_NAMES } = require('./constants') + +var DEFAULT_NETWORK_TYPE = 'prod' + +const ADDRESS_TYPE_INFO = {} +ADDRESS_TYPE_INFO['00'] = { + network: NETWORKS.MAINNET, + type: ADDRESS_TYPES.P2PKH +} +ADDRESS_TYPE_INFO['05'] = { + network: NETWORKS.MAINNET, + type: ADDRESS_TYPES.P2SH +} +ADDRESS_TYPE_INFO['6f'] = { + network: NETWORKS.TESTNET, + type: ADDRESS_TYPES.P2PKH +} +ADDRESS_TYPE_INFO['c4'] = { + network: NETWORKS.TESTNET, + type: ADDRESS_TYPES.P2SH +} + +function getDecoded (address) { + try { + return base58.decode(address) + } catch (e) { + // if decoding fails, assume invalid address + return null + } +} + +function getAddressType (address) { + var expectedLength = 25 + var decoded = getDecoded(address) + + if (decoded) { + var length = decoded.length + + if (length !== expectedLength) { + return null + } + + var checksum = toHex(decoded.slice(length - 4, length)), + body = toHex(decoded.slice(0, length - 4)), + goodChecksum = sha256Checksum(body) + + return checksum === goodChecksum ? toHex(decoded.slice(0, expectedLength - 24)) : null + } + + return null +} + +function isValidP2PKHandP2SHAddress (address, networkType) { + networkType = networkType || DEFAULT_NETWORK_TYPE + + var addressType = getAddressType(address) + + if (addressType && ADDRESS_TYPE_INFO[addressType]) { + if (networkType === NETWORKS.MAINNET || networkType === NETWORKS.TESTNET) { + return ADDRESS_TYPE_INFO[addressType].network == networkType + } else { + return true + } + } + + return false +} + +function getAddressInfo (address) { + const addressType = getAddressType(address) + const addressInfo = ADDRESS_TYPE_INFO[addressType] + if (!addressInfo) { + return null + } + + let decodedAddress = Buffer.from(getDecoded(address)) + let hash = decodedAddress.slice(1, 21).toString('hex') + let fieldName = HASH_FIELD_NAMES[addressInfo.type] + addressInfo[fieldName] = hash + + return addressInfo +} + +module.exports = { + isValid: isValidP2PKHandP2SHAddress, + getAddressInfo: getAddressInfo +} diff --git a/src/_utils/pegin-address-verifier/crypto/segwit-addr.js b/src/_utils/pegin-address-verifier/crypto/segwit-addr.js new file mode 100644 index 00000000..7b470ec4 --- /dev/null +++ b/src/_utils/pegin-address-verifier/crypto/segwit-addr.js @@ -0,0 +1,142 @@ +// Copyright (c) 2017 Pieter Wuille +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +var bech32 = require('./bech32'); +let { ADDRESS_TYPES, NETWORKS } = require('./constants'); + +const PREFIXES = { + BC: 'bc', + TB: 'tb', + BCRT: 'bcrt' +} + +const NETWORK_BY_PREFIX = {}; +NETWORK_BY_PREFIX[PREFIXES.BC] = NETWORKS.MAINNET; +NETWORK_BY_PREFIX[PREFIXES.TB] = NETWORKS.TESTNET; +NETWORK_BY_PREFIX[PREFIXES.BCRT] = NETWORKS.REGTEST; + +const PREFIX_BY_NETWORK = {}; +PREFIX_BY_NETWORK[NETWORKS.MAINNET] = PREFIXES.BC; +PREFIX_BY_NETWORK[NETWORKS.TESTNET] = PREFIXES.TB; +PREFIX_BY_NETWORK[NETWORKS.REGTEST] = PREFIXES.BCRT; + +function convertbits (data, frombits, tobits, pad) { + var acc = 0; + var bits = 0; + var ret = []; + var maxv = (1 << tobits) - 1; + for (var p = 0; p < data.length; ++p) { + var value = data[p]; + if (value < 0 || (value >> frombits) !== 0) { + return null; + } + acc = (acc << frombits) | value; + bits += frombits; + while (bits >= tobits) { + bits -= tobits; + ret.push((acc >> bits) & maxv); + } + } + if (pad) { + if (bits > 0) { + ret.push((acc << (tobits - bits)) & maxv); + } + } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { + return null; + } + return ret; +} + +function decode (hrp, addr) { + var dec = bech32.decode(addr); + if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) { + return null; + } + var res = convertbits(dec.data.slice(1), 5, 8, false); + if (res === null || res.length < 2 || res.length > 40) { + return null; + } + if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { + return null; + } + return {version: dec.data[0], program: res}; +} + +function encode (hrp, version, program) { + var ret = bech32.encode(hrp, [version].concat(convertbits(program, 8, 5, true))); + if (decode(hrp, ret) === null) { + return null; + } + return ret; +} + +function isValidAddress(address, networkType) { + let hrp = null; + var ret = null; + + if (Object.values(NETWORKS).includes(networkType)) { + hrp = PREFIX_BY_NETWORK[networkType]; + ret = decode(hrp, address); + } else { + let prefix = getAddressPrefix(address).toLowerCase(); + if (Object.values(PREFIXES).includes(prefix)) { + hrp = prefix; + ret = decode(hrp, address); + } + } + + if (ret === null) { + return false; + } + + var recreate = encode(hrp, ret.version, ret.program); + return recreate === address.toLowerCase(); +} + +function getAddressInfo(address) { + if (!address) { + return null; + } + let prefix = getAddressPrefix(address); + let network = NETWORK_BY_PREFIX[prefix.toLowerCase()]; + + if (network && isValidAddress(address, network)) { + return { network, type: ADDRESS_TYPES.BECH32 }; + } + return null; +} + +function getAddressPrefix(address) { + let prefix = address.toString().substring(0,2); + if (prefix === PREFIXES.BC) { + // Could be mainnet or regtest + let prefixRegtest = address.toString().substring(0,4); + if (prefixRegtest === PREFIXES.BCRT) { + prefix = PREFIXES.BCRT; + } + } + + return prefix; +} + +module.exports = { + isValidAddress: isValidAddress, + getAddressInfo: getAddressInfo +}; diff --git a/src/_utils/pegin-address-verifier/crypto/utils.js b/src/_utils/pegin-address-verifier/crypto/utils.js new file mode 100644 index 00000000..7a2d13df --- /dev/null +++ b/src/_utils/pegin-address-verifier/crypto/utils.js @@ -0,0 +1,41 @@ +var jsSHA = require('jssha/sha256'); +var base58 = require('./base58'); + +function numberToHex (number) { + var hex = Math.round(number).toString(16); + if(hex.length === 1) { + hex = '0' + hex; + } + return hex; +} + +function sha256(hexString) { + var sha = new jsSHA('SHA-256', 'HEX'); + sha.update(hexString); + return sha.getHash('HEX'); +} + +function toHex(arrayOfBytes) { + var hex = ''; + for(var i = 0; i < arrayOfBytes.length; i++) { + hex += numberToHex(arrayOfBytes[i]); + } + return hex; +} + +function sha256Checksum(payload) { + return sha256(sha256(payload)).substr(0, 8); +} + +function decodeWifPrivateKey(wifPrivateKey) { + let decodedPrivateKey = base58.decode(wifPrivateKey); + let privateKey = decodedPrivateKey.slice(1, decodedPrivateKey.length - 5); + + return toHex(privateKey); +} + +module.exports = { + toHex, + sha256Checksum, + decodeWifPrivateKey +}; diff --git a/src/_utils/pegin-address-verifier/pegin-address-verifier.js b/src/_utils/pegin-address-verifier/pegin-address-verifier.js new file mode 100644 index 00000000..90d2f7bf --- /dev/null +++ b/src/_utils/pegin-address-verifier/pegin-address-verifier.js @@ -0,0 +1,70 @@ +const p2pkhP2sh = require('./crypto/p2pkh-p2sha'); +const segwit = require('./crypto/segwit-addr'); +const { ADDRESS_TYPES, ADDRESS_TYPES_CODES } = require('./crypto/constants'); + +const RSKT_PREFIX_HEX = '52534b54'; // 'RSKT' prefix encoded in hex. Check https://github.com/rsksmart/RSKIPs/blob/2c994cc108885ccc5a116e4aee8c073b5eca5682/IPs/RSKIP170.md#specification for more details +const RSKT_PROTOCOL_VERSION = '01'; + +const isValidAddress = (address, networkType) => { + return p2pkhP2sh.isValid(address, networkType) || + segwit.isValidAddress(address, networkType); +}; + +const getAddressInformation = (address) => { + return p2pkhP2sh.getAddressInfo(address) || + segwit.getAddressInfo(address); +}; + +const canPegIn = (addressInfo) => { + return addressInfo && + addressInfo.type == ADDRESS_TYPES.P2PKH || + addressInfo.type == ADDRESS_TYPES.P2SH; +}; + +/** + * Creates the pegin v1 data for the given {rskDestinationAddress} and optionally the {btcRefundAddress}. + * @param {string} rskDestinationAddress + * @param {string?} btcRefundAddress + * @returns {string} The pegin v1 data. + */ +const createPeginV1TxData = (rskDestinationAddress, btcRefundAddress) => { + + if(!rskDestinationAddress) { + throw new Error('RSK destination address is required'); + } + + let data = `${RSKT_PREFIX_HEX}${RSKT_PROTOCOL_VERSION}`; + + if (rskDestinationAddress.startsWith('0x')) { + rskDestinationAddress = rskDestinationAddress.substring(2); + } + + data += rskDestinationAddress; + + if (btcRefundAddress) { + const refundAddressInfo = getAddressInformation(btcRefundAddress); + if (refundAddressInfo) { + switch (refundAddressInfo.type) { + case 'p2pkh': + data += ADDRESS_TYPES_CODES.p2pkh + refundAddressInfo.scriptPubKey; + break; + case 'p2sh': + data += ADDRESS_TYPES_CODES.p2sh + refundAddressInfo.scriptHash; + break; + default: + throw new Error(`Unsupported btc refund address type: ${refundAddressInfo.type}`); + } + } else { + throw new Error(`Could not get address information for ${btcRefundAddress}`); + } + } + + return data.toLocaleLowerCase(); +}; + +module.exports = { + isValidAddress, + getAddressInformation, + canPegIn, + createPeginV1TxData, +}; diff --git a/src/components/AddressVerifier/index.js b/src/components/AddressVerifier/index.js new file mode 100644 index 00000000..21a1d273 --- /dev/null +++ b/src/components/AddressVerifier/index.js @@ -0,0 +1,55 @@ +import React, { useState, useEffect, useRef } from 'react' +import { getAddressInformation, canPegIn } from '/src/_utils/pegin-address-verifier/pegin-address-verifier' + +export default function AddressVerifier () { + + const [address, setAddress] = useState('') + const [addressInfo, setAddressInfo] = useState('') + const inputRef = useRef(null) + const checkAddress = (e) => { + e.preventDefault() + const address = inputRef.current.value; + setAddress(address) + setAddressInfo(getAddressInformation(address)) + } + + const AddressInfoResult = ({ info }) => { + const [result, setResult] = useState('') + + useEffect(() => { + const displayAddress = `${address}`; + + if (info === null) { + setResult(`The address ${displayAddress} is not valid.`) + } else if (info?.type) { + let displayAddressType = `${info.type.toUpperCase()}` + let displayNetwork = `${info.network.charAt(0).toUpperCase()}${info.network.slice(1)}` + + let isCanPegIn = canPegIn(info) + if (isCanPegIn) { + if (info.type == 'p2pkh') { + setResult(`The address ${displayAddress} is a valid ${displayAddressType} address, and may peg in on ${displayNetwork}.`) + } else { + setResult(`The address ${displayAddress} is a valid ${displayAddressType} address, however, may not peg in on ${displayNetwork}. Please check the compatibility matrix.`) + } + } else { + setResult(`The address ${displayAddress} is a valid ${displayAddressType} address, however, will not peg in on ${displayNetwork}.
Do not use this wallet, your BTC will be lost. Please check the compatibility matrix.`) + } + } + }, [info]) + + return result && ( +
+ ) + } + + return ( +
+
+ + +
+ + + ) +} diff --git a/src/theme/MDXComponents.js b/src/theme/MDXComponents.js index 6dd5a53a..c8d305a1 100644 --- a/src/theme/MDXComponents.js +++ b/src/theme/MDXComponents.js @@ -15,14 +15,14 @@ import Shield from "/src/components/ShieldsBadge"; import Button from "/src/components/Button"; import CardsGrid from "/src/components/CardsGrid"; import CardsGridItem from "/src/components/CardsGrid/Card"; - import Steps from "/src/components/Steps"; import Step from "/src/components/Steps/Step"; +import AddressVerifier from "/src/components/AddressVerifier"; export default { // Re-use the default mapping ...MDXComponents, // Map the "" tag to our Highlight component // `Highlight` will receive all props that were passed to `` in MDX - Carousel, CarouselItem, Tabs, TabItem, Accordion, Card, Quote, Video, Filter, FilterItem, Button, CardsGrid, CardsGridItem, Shield, Steps, Step + Carousel, CarouselItem, Tabs, TabItem, Accordion, Card, Quote, Video, Filter, FilterItem, Button, CardsGrid, CardsGridItem, Shield, Steps, Step, AddressVerifier }; diff --git a/yarn.lock b/yarn.lock index 9ccac9c5..1f215f69 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2802,6 +2802,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" @@ -2911,6 +2916,14 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -4843,6 +4856,11 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0, ignore@^5.2.4: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" @@ -5259,6 +5277,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jssha@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jssha/-/jssha-3.3.1.tgz#c5b7fc7fb9aa745461923b87df0e247dd59c7ea8" + integrity sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ== + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" From 983571ac2ab94507fa86d718c0e40822613db650 Mon Sep 17 00:00:00 2001 From: alexcss Date: Tue, 12 Nov 2024 16:17:36 +0200 Subject: [PATCH 2/5] Peg in Address Verifier add result styles --- src/components/AddressVerifier/index.js | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/components/AddressVerifier/index.js b/src/components/AddressVerifier/index.js index 21a1d273..f6d793c7 100644 --- a/src/components/AddressVerifier/index.js +++ b/src/components/AddressVerifier/index.js @@ -1,27 +1,40 @@ import React, { useState, useEffect, useRef } from 'react' import { getAddressInformation, canPegIn } from '/src/_utils/pegin-address-verifier/pegin-address-verifier' +import Admonition from '@theme/Admonition' export default function AddressVerifier () { const [address, setAddress] = useState('') const [addressInfo, setAddressInfo] = useState('') const inputRef = useRef(null) + const clearForm = (e) => { + setAddress('') + setAddressInfo('') + } const checkAddress = (e) => { e.preventDefault() - const address = inputRef.current.value; + if (!inputRef?.current?.value) return + + const address = inputRef.current.value.trim() setAddress(address) setAddressInfo(getAddressInformation(address)) } const AddressInfoResult = ({ info }) => { const [result, setResult] = useState('') + const [resultType, setResultType] = useState('') + const [resultTitle, setResultTitle] = useState('') useEffect(() => { - const displayAddress = `${address}`; + const displayAddress = `${address}` if (info === null) { setResult(`The address ${displayAddress} is not valid.`) + setResultType('warning') + setResultTitle('Not valid') } else if (info?.type) { + setResultType('success') + setResultTitle('Valid') let displayAddressType = `${info.type.toUpperCase()}` let displayNetwork = `${info.network.charAt(0).toUpperCase()}${info.network.slice(1)}` @@ -39,15 +52,20 @@ export default function AddressVerifier () { }, [info]) return result && ( -
+ +
+
) } return (
-
+
- +
+ + +
From 3cf09920f0d522b0fdc16fbce14f45ca041a9438 Mon Sep 17 00:00:00 2001 From: alexcss Date: Wed, 13 Nov 2024 11:39:48 +0200 Subject: [PATCH 3/5] RNS domain search form --- docs/01-concepts/rif-suite/rns/index.md | 76 ++++++++++--------------- src/components/RNSDomainSearch/index.js | 11 ++++ src/scss/base/_forms.scss | 4 +- src/scss/base/_theme-variables.scss | 3 + src/theme/MDXComponents.js | 4 +- 5 files changed, 51 insertions(+), 47 deletions(-) create mode 100644 src/components/RNSDomainSearch/index.js diff --git a/docs/01-concepts/rif-suite/rns/index.md b/docs/01-concepts/rif-suite/rns/index.md index 9aca5a8b..6723bd59 100644 --- a/docs/01-concepts/rif-suite/rns/index.md +++ b/docs/01-concepts/rif-suite/rns/index.md @@ -8,55 +8,41 @@ description: "Information about the RIF token, where to obtain it, how to transf RNS provides an architecture which enables the identification of blockchain addresses by human-readable names. -