Bitcoinjs-lib: Add an OmniLayer example to tests

Created on 15 Aug 2018  Â·  50Comments  Â·  Source: bitcoinjs/bitcoinjs-lib

I wanted to use this OmniLayer protocol, but have found no examples in the whole internet. I think it would be good to include such examples in the tests.

Here's a small snippet: https://gist.github.com/caffeinum/f64a51ce55d5ac9075bb2f5f2f439c0d

external how to / question / docs

Most helpful comment

@caffeinum Modified your example to work with bitcoinjs-lib v4 (Marked changes with NEW**)

const bitcoin = require('bitcoinjs-lib')
const request = require('request-promise-native')
const net = process.env.NETWORK === 'testnet'
  ? bitcoin.networks.testnet
  : bitcoin.networks.bitcoin

const API = net === bitcoin.networks.testnet
  ? `https://test-insight.swap.online/insight-api`
  : `https://insight.bitpay.com/api`

const fetchUnspents = (address) =>
  request(`${API}/addr/${address}/utxo/`).then(JSON.parse)

const broadcastTx = (txRaw) =>
  request.post(`${API}/tx/send`, {
    json: true,
    body: {
      rawtx: txRaw,
    },
  })

const createSimpleSend = async (fetchUnspents, alice_pair, recipient_address/*, amount = 10*/) => {

  const tx = new bitcoin.TransactionBuilder(net)

  const alice_p2pkh = bitcoin.payments.p2pkh({
    pubkey: alice_pair.publicKey,
    network: net
  }).address // NEW** New Payments API for p2pkh
  const unspents = await fetchUnspents(alice_p2pkh)

  const fundValue     = 546 // dust
  const feeValue      = 5000
  const totalUnspent  = unspents.reduce((summ, { satoshis }) => summ + satoshis, 0)
  const skipValue     = totalUnspent - fundValue - feeValue

  if (totalUnspent < feeValue + fundValue) {
    throw new Error(`Total less than fee: ${totalUnspent} < ${feeValue} + ${fundValue}`)
  }

  unspents.forEach(({ txid, vout }) => tx.addInput(txid, vout, 0xfffffffe))

  const simple_send = [
    "6f6d6e69", // omni
    "0000",     // version
    "00000000001f", // 31 for Tether
    "000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
  ].join('')

  const data = [ Buffer.from(simple_send, "hex") ] // NEW** data must be an Array(Buffer)

  const omniOutput = bitcoin.payments.embed({ data }).output // NEW** Payments API

  tx.addOutput(recipient_address, fundValue) // should be first!
  tx.addOutput(omniOutput, 0)

  tx.addOutput(alice_p2pkh, skipValue)

  // NEW** tx.inputs was deprecated, since you use unspents 1-for-1 to make inputs I used unspents.
  unspents.forEach((unspent, index) => {
    tx.sign(index, alice_pair)
  })

  return tx
}

// Construct tx
const alice = bitcoin.ECPair.fromWIF(process.env.ALICE_WIF, net)
const bobby = bitcoin.ECPair.makeRandom({ network: net })
const amount = null // not used

// NEW** Used new payments API for bobby
const omni_tx = createSimpleSend(fetchUnspents, alice, bitcoin.payments.p2pkh({ pubkey: bobby.publicKey, network: net }).address, amount)

const auto_send = false

omni_tx.then(tx => {
  const txRaw = tx.buildIncomplete()

  console.log('hash', txRaw.getId())

  console.log(`"${txRaw.toHex()}"`)
  console.log(txRaw)

  if (auto_send) {
    broadcastTx(txRaw.toHex())
  }
})

All 50 comments

Undecided whether our examples are the right place for that...

That makes sense
maybe at least some reference in the OP_RETURN section. I had a hard time breaking this and wanted to share

@caffeinum have you tried the new payments API? Specifically bitcoin.payments.embed?

@caffeinum Modified your example to work with bitcoinjs-lib v4 (Marked changes with NEW**)

const bitcoin = require('bitcoinjs-lib')
const request = require('request-promise-native')
const net = process.env.NETWORK === 'testnet'
  ? bitcoin.networks.testnet
  : bitcoin.networks.bitcoin

const API = net === bitcoin.networks.testnet
  ? `https://test-insight.swap.online/insight-api`
  : `https://insight.bitpay.com/api`

const fetchUnspents = (address) =>
  request(`${API}/addr/${address}/utxo/`).then(JSON.parse)

const broadcastTx = (txRaw) =>
  request.post(`${API}/tx/send`, {
    json: true,
    body: {
      rawtx: txRaw,
    },
  })

const createSimpleSend = async (fetchUnspents, alice_pair, recipient_address/*, amount = 10*/) => {

  const tx = new bitcoin.TransactionBuilder(net)

  const alice_p2pkh = bitcoin.payments.p2pkh({
    pubkey: alice_pair.publicKey,
    network: net
  }).address // NEW** New Payments API for p2pkh
  const unspents = await fetchUnspents(alice_p2pkh)

  const fundValue     = 546 // dust
  const feeValue      = 5000
  const totalUnspent  = unspents.reduce((summ, { satoshis }) => summ + satoshis, 0)
  const skipValue     = totalUnspent - fundValue - feeValue

  if (totalUnspent < feeValue + fundValue) {
    throw new Error(`Total less than fee: ${totalUnspent} < ${feeValue} + ${fundValue}`)
  }

  unspents.forEach(({ txid, vout }) => tx.addInput(txid, vout, 0xfffffffe))

  const simple_send = [
    "6f6d6e69", // omni
    "0000",     // version
    "00000000001f", // 31 for Tether
    "000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
  ].join('')

  const data = [ Buffer.from(simple_send, "hex") ] // NEW** data must be an Array(Buffer)

  const omniOutput = bitcoin.payments.embed({ data }).output // NEW** Payments API

  tx.addOutput(recipient_address, fundValue) // should be first!
  tx.addOutput(omniOutput, 0)

  tx.addOutput(alice_p2pkh, skipValue)

  // NEW** tx.inputs was deprecated, since you use unspents 1-for-1 to make inputs I used unspents.
  unspents.forEach((unspent, index) => {
    tx.sign(index, alice_pair)
  })

  return tx
}

// Construct tx
const alice = bitcoin.ECPair.fromWIF(process.env.ALICE_WIF, net)
const bobby = bitcoin.ECPair.makeRandom({ network: net })
const amount = null // not used

// NEW** Used new payments API for bobby
const omni_tx = createSimpleSend(fetchUnspents, alice, bitcoin.payments.p2pkh({ pubkey: bobby.publicKey, network: net }).address, amount)

const auto_send = false

omni_tx.then(tx => {
  const txRaw = tx.buildIncomplete()

  console.log('hash', txRaw.getId())

  console.log(`"${txRaw.toHex()}"`)
  console.log(txRaw)

  if (auto_send) {
    broadcastTx(txRaw.toHex())
  }
})

@dcousens

  1. if data is a Buffer, I think we should assume it should be a single push and just make it into a single item Array automatically.
  2. TransactionBuilder.inputs.forEach is something I see a lot... being only used to grab the index... (a lot of people now adays hate for (var i = 0; i < x; i++) loops... lol

if data is a Buffer, I think we should assume it should be a single push and just make it into a single item Array automatically.

I don't know if that is great idea...

TransactionBuilder.inputs.forEach

I don't know why.
If you had an inputs array to begin with (unspents!), you should use that no?

If you had an inputs array to begin with (unspents!), you should use that no?

This assumes you use all items of the Array. (array.length === txb.inputCount)

Perhaps a getter for txb.inputCount and outputCount that grabs the current count internally...

Then we could do:

Array(txb.inputCount).fill(0).forEach((item, index) => {
    console.log(index)
})

But at that point, a for loop looks cleaner and easier to understand... :-/

@junderw yes, you should always use all the unspents provided. If you don't want to use them all... filter them to what you need.

See coinselect for that workflow...

you should always use all the unspents provided

What about when they don't have the unspents? Like a rawtx.

If we don't want them to touch the internals of Tx and Txb then how should they gather how many inputs they have?

@junderw great question.
I don't know

We don't want to encourage merely iterating over the equivalent of txb.inputs, as, it means they might not have checked what those inputs are...

PSBT to the rescue!

@junderw is it though?

@dcousens hahahahahahahahahaha

Well............... it's better than not having it IMO.

" tx.addOutput(recipient_address, fundValue) // should be first! ",why that it should be first , i have used the code ,but the signd transaction is something wrong at the referenceaddress .

Read the Omni Protocol documents.

It should be first because the Omni protocol requires it.

@Nick-49 which bitcoinjs-lib version you were using? My snippet does not work with 4.0 version yet, but there is an updated version above: https://github.com/bitcoinjs/bitcoinjs-lib/issues/1176#issuecomment-419014085

I have found the "bug" of my code . And i have solved it. thank you~ @caffeinum @junderw

Hi,
What mean "000000003B9ACA00" // amount = 10 * 100 000 000 in HEX ?

It should be change dynamically?

@ssssssu12 yes, its the amount of Omni tokens to send

This is a detailed demo

@yugasun txb.addInput second arg is not amount, it's the UTXO vout index.

@junderw thanks for your correction, I made a mistake.

@caffeinum Modified your example to work with bitcoinjs-lib v4 (Marked changes with NEW**)

const bitcoin = require('bitcoinjs-lib')
const request = require('request-promise-native')
const net = process.env.NETWORK === 'testnet'
  ? bitcoin.networks.testnet
  : bitcoin.networks.bitcoin

const API = net === bitcoin.networks.testnet
  ? `https://test-insight.swap.online/insight-api`
  : `https://insight.bitpay.com/api`

const fetchUnspents = (address) =>
  request(`${API}/addr/${address}/utxo/`).then(JSON.parse)

const broadcastTx = (txRaw) =>
  request.post(`${API}/tx/send`, {
    json: true,
    body: {
      rawtx: txRaw,
    },
  })

const createSimpleSend = async (fetchUnspents, alice_pair, recipient_address/*, amount = 10*/) => {

  const tx = new bitcoin.TransactionBuilder(net)

  const alice_p2pkh = bitcoin.payments.p2pkh({
    pubkey: alice_pair.publicKey,
    network: net
  }).address // NEW** New Payments API for p2pkh
  const unspents = await fetchUnspents(alice_p2pkh)

  const fundValue     = 546 // dust
  const feeValue      = 5000
  const totalUnspent  = unspents.reduce((summ, { satoshis }) => summ + satoshis, 0)
  const skipValue     = totalUnspent - fundValue - feeValue

  if (totalUnspent < feeValue + fundValue) {
    throw new Error(`Total less than fee: ${totalUnspent} < ${feeValue} + ${fundValue}`)
  }

  unspents.forEach(({ txid, vout }) => tx.addInput(txid, vout, 0xfffffffe))

  const simple_send = [
    "6f6d6e69", // omni
    "0000",     // version
    "00000000001f", // 31 for Tether
    "000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
  ].join('')

  const data = [ Buffer.from(simple_send, "hex") ] // NEW** data must be an Array(Buffer)

  const omniOutput = bitcoin.payments.embed({ data }).output // NEW** Payments API

  tx.addOutput(recipient_address, fundValue) // should be first!
  tx.addOutput(omniOutput, 0)

  tx.addOutput(alice_p2pkh, skipValue)

  // NEW** tx.inputs was deprecated, since you use unspents 1-for-1 to make inputs I used unspents.
  unspents.forEach((unspent, index) => {
    tx.sign(index, alice_pair)
  })

  return tx
}

// Construct tx
const alice = bitcoin.ECPair.fromWIF(process.env.ALICE_WIF, net)
const bobby = bitcoin.ECPair.makeRandom({ network: net })
const amount = null // not used

// NEW** Used new payments API for bobby
const omni_tx = createSimpleSend(fetchUnspents, alice, bitcoin.payments.p2pkh({ pubkey: bobby.publicKey, network: net }).address, amount)

const auto_send = false

omni_tx.then(tx => {
  const txRaw = tx.buildIncomplete()

  console.log('hash', txRaw.getId())

  console.log(`"${txRaw.toHex()}"`)
  console.log(txRaw)

  if (auto_send) {
    broadcastTx(txRaw.toHex())
  }
})

It is generate a transaction successfully but that Tx Hash not reflect on Omni Blockchain.
screenshot from 2019-01-08 16-23-33

https://www.omniexplorer.info/search/ba2ae595f03874b7773548102e12cfe3d6cf0be85791f81b76ed1b2d85b10cce

@rohitsahu21 well, tx was not published to bitpay either: https://insight.bitpay.com/tx/ba2ae595f03874b7773548102e12cfe3d6cf0be85791f81b76ed1b2d85b10cce

Did you use NETWORK=mainnet?

@caffeinum No i'm using Testnet for Testing purpose

@rohitsahu21 omniexplorer doesn't work for testnet. You need to run your own OmniLayer node if you want to try OMNI tokens on bitcoin testnet. Also, I didn't test this script on testnet, you should check all the values. You can contact me at telegram @caffeinum if you need some extra help.

Hi @caffeinum @junderw ,

I'm looking to develop a USDT wallet (NodeJs) without the need to setup my own Omnilayer node. Would really appreciate for any advice or help regarding the following:

  1. What are the modifications required if i need to have USDT(propertyid: 31) signed transaction prepared offline so that i could use bitpay or omniexplorer's pushtx API to broadcast the transaction on mainnet?
  2. Why is the fee value fixed at 5000? Did you fix the value at 5000 satoshi since the network fee which is expected to consume would be below that number?
  3. Is there an estimate fee API which could be written and is there an example?

Any help would be greatly appreciate you guys!

Thanks!

  1. the above example is for USDT
  2. idk why 5000 was chosen, ask the person who made the example.
  3. estimatesmartfee on Bitcoin Core will give you a good BTC/kB rate, then all you need to do is multiply by how many kB your Transaction vsize is, and that is how much you should use.

https://www.bitgo.com/api/v1/tx/fee

This is also a good API, Bitgo has an ok fee estimator.

feeByBlockTarget["3"] for instance is "satoshis per kB cost if you want your transaction confirmed within the next 3 blocks"

but imo, Bitgo overestimates a tad, so 3 should get in the next block most of the time.

@zinxer

  1. What are the modifications required if i need to have USDT(propertyid: 31) signed transaction prepared offline so that i could use bitpay or omniexplorer's pushtx API to broadcast the transaction on mainnet?

The example works offline! Only two functions: fetchUnspents, broadcastTx need connection. You can extract or cache needed values, or pass them via other means.

  1. Why is the fee value fixed at 5000? Did you fix the value at 5000 satoshi since the network fee which is expected to consume would be below that number?

That was arbitrary, you can use any value.

However, there's one pitfall: to estimate fee well, you need to know tx size, but to know tx size, you need to know all the inputs and outputs. However, you could use this simple formula for standard P2SH/P2PKH, only modify it to include OP_RETURN extra size.

const txSize = numInputs * 146 + numOutputsWithoutOmni * 33 + 10 + omniOutputSize

Extra reading:

  1. Is there an estimate fee API which could be written and is there an example?

I use these nodes for estimation:

https://bitcoinfees.earn.com/api/v1/fees/recommended
https://api.blockcypher.com/v1/btc/main

They give estimate in sat/byte (sat/kb for blockcypher), so to know actual fee, you need to multiply that by tx size. See above ^

P.S. Also, as for offline signing, see Metamask's PR for external signers: https://github.com/MetaMask/metamask-extension/pull/6143, and github.com/flightwallet and https://www.parity.io/signer/ as an examples of offline signers. Probably you can benefit from there examples if you're doing offline wallet

Hi @junderw @caffeinum ,

It seems like it should be this:

                const simple_send = [
                    "6f6d6e69",    // omni
                    "0000",    // version
                    "00000000001f",    // 31 for Tether
                    "00000000",    //8 zeros before 2s complement HEX
                    "<amount HEX in signed 2s complement>"    // amount = <amount> * 100 000 000 in HEX
                ].join('')

instead of:

const simple_send = [
"6f6d6e69", // omni
"0000", // version
"00000000001f", // 31 for Tether
"000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
].join('')

The only problem i'm facing now is to programmatically convert decimals to HEX signed 2s complement string.

No.

You need to encode into 8 bytes if you want to support omni.

Your idea to use only 4 bytes will break for values over 42.94 USDT

6 bytes can support up to 2.8 million USDT ish.

but you should support 8 bytes using a bigint or bignumber library.

Noted @junderw , i'm looking for a function to convert the HEX value with padded leading zeros to fill an 8-byte length amount.

Update:
I've solved this by:

  1. Checking the byte size of the HEX value by using Buffer.byteLength(<amt>, 'hex')
  2. Do a while loop by padding leading zeros to the HEX value until the size is 8 byte.

@zinxer here's my version of toPaddedHexString:

const toPaddedHexString = (num, len) => {
    const str = num.toString(16)
    return "0".repeat(len - str.length) + str
}

Usage:

const simple_send = [
    "6f6d6e69", // omni
    "0000",     // tx type
    "0000",     // version
    // "0000001f", // 31 for Tether
    toPaddedHexString(coin, 8),
    // "000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
    toPaddedHexString(Math.floor(amount * 100000000), 16),
].join('')

(from https://github.com/swaponline/swap.core/tree/master/src/swap.swaps/usdt)

Noted thanks guys!

Was wondering how would adding another wallet as part of the input where it's funds are used to pay the network fee while the other's btc is used as dust.

  1. How to add another wallet as a sender and sign the transaction.
  2. How to prioritise completely clear out walletA and remaining to use WalletB. (E.g. WalletA's btc used for dust and WalletB's btc is used for network fee to send USDT to a single recipient address.)

Thanks,
Matt

Updated the example to use the new PSBT from v5.1

const bitcoin = require('bitcoinjs-lib')
const request = require('request-promise-native')
const net = process.env.NETWORK === 'testnet'
  ? bitcoin.networks.testnet
  : bitcoin.networks.bitcoin

const API = net === bitcoin.networks.testnet
  ? `https://test-insight.swap.online/insight-api`
  : `https://insight.bitpay.com/api`

const fetchUnspents = (address) =>
  request(`${API}/addr/${address}/utxo/`).then(JSON.parse)

// *NEW need full raw tx for all non-segwit inputs (to verify the value before signing)
const getRawTx = (txid) =>
  request(`${API}/rawtx/${txid}/`).then(JSON.parse).then(data => Buffer.from(data.rawtx, 'hex'))

const broadcastTx = (txRaw) =>
  request.post(`${API}/tx/send`, {
    json: true,
    body: {
      rawtx: txRaw,
    },
  })

const createSimpleSend = async (fetchUnspents, alice_pair, recipient_address/*, amount = 10*/) => {

  // *NEW PSBT class
  const psbt = new bitcoin.Psbt({ network: net })

  const alice_p2pkh = bitcoin.payments.p2pkh({
    pubkey: alice_pair.publicKey,
    network: net
  }).address
  const unspents = await fetchUnspents(alice_p2pkh)

  const fundValue     = 546 // dust
  const feeValue      = 5000
  const totalUnspent  = unspents.reduce((summ, { satoshis }) => summ + satoshis, 0)
  const skipValue     = totalUnspent - fundValue - feeValue

  if (totalUnspent < feeValue + fundValue) {
    throw new Error(`Total less than fee: ${totalUnspent} < ${feeValue} + ${fundValue}`)
  }

  for (let i = 0; i < unspents.length; i++) {
    const nonWitnessUtxo = await getRawTx(unspents[i].txid)
    psbt.addInput({
      hash: unspents[i].txid,
      index: unspents[i].vout,
      sequence: 0xfffffffe,
      nonWitnessUtxo, // *NEW This will allow us to verify you are signing the correct values for inputs
    })
  }

  const simple_send = [
    "6f6d6e69", // omni
    "0000",     // version
    "00000000001f", // 31 for Tether
    "000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
  ].join('')

  const data = [ Buffer.from(simple_send, "hex") ]

  const omniOutput = bitcoin.payments.embed({ data }).output

  psbt.addOutput({ address: recipient_address, value: fundValue }) // should be first!
  psbt.addOutput({ script: omniOutput, value: 0 })

  psbt.addOutput({ address: alice_p2pkh, value: skipValue })

  // *NEW sign all inputs with one method call
  psbt.signAllInputs(alice_pair)

  return psbt
}

// Construct tx
const alice = bitcoin.ECPair.fromWIF(process.env.ALICE_WIF, net)
const bobby = bitcoin.ECPair.makeRandom({ network: net })
const amount = null // not used

const omni_tx = createSimpleSend(fetchUnspents, alice, bitcoin.payments.p2pkh({ pubkey: bobby.publicKey, network: net }).address, amount)

const auto_send = false

omni_tx.then(psbt => {
  // *NEW must finalize before TX extraction. (this helps for multisig)
  const txRaw = psbt.finalizeAllInputs().extractTransaction()

  console.log('hash', txRaw.getId())

  console.log(`"${txRaw.toHex()}"`)
  console.log(txRaw)

  if (auto_send) {
    broadcastTx(txRaw.toHex())
  }
})

You didn't broadcast it to the network.

I broadcasted it for you. it should show up soon.

@junderw
Excuse me, The following error occurred when I executed the above script:

(node:19020) UnhandledPromiseRejectionWarning: RequestError: Error: getaddrinfo ENOTFOUND test-insight.swap.online

I tested this script in January and it was ok, but not now, do you have a good solution?

something's wrong with the remote API you're using

@junderw Yes, I also see that this API cannot be accessed. Do you have any other remote API that can be used?Thank you very much!

No... unfortunately a lot of the testnet block explorers are unreliable.

For bitcoinjs-lib we use regtest-server docker container. So when we run integration tests a small docker container with a simple REST server and a regtest bitcoin node are spun up and you can use the regtest-client library to interface with it.

Check the integration tests to see how it is used.

$ docker pull junderw/bitcoinjs-regtest-server
$ docker run -d -p 127.0.0.1:8080:8080 junderw/bitcoinjs-regtest-server

Then once you have this running locally,

import { RegtestUtils } from 'regtest-client';

const APIPASS = 'satoshi';
const APIURL = 'http://127.0.0.1:8080/1';

const regtestUtils = new RegtestUtils({ APIPASS, APIURL });

Then you can do things like

await regtestUtils.mine(10)

To mine 10 blocks etc.

It is much better for testing / messing around.

however, this server does not verify Omni protocol... sooooooo, I don't know what to tell you about that.

Yes, thank you.

hello:
this is my wif L3w9mnJVSqYM9adQomcbwXPRj1rjui5aoVXXnmQ5Yf8qLfy1ZYyL
myAddress = ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn

recipient_address = mm1oDPm8vjBfdv92yaMacMGfwpdvfFTeoM
this is my code

const WIF = 'L3w9mnJVSqYM9adQomcbwXPRj1rjui5aoVXXnmQ5Yf8qLfy1ZYyL'

const alice = bitcoin.ECPair.fromWIF(WIF)
const psbt = new bitcoin.Psbt({ network: bitcoin.networks.testnet })

utxo.forEach((item, index, arr) => {
    psbt.addInput({
        hash: item.txid,
        index: item.vout,
        nonWitnessUtxo: Buffer.from(item.raw, 'hex'),
    })
})
const fee = 1000
const reback = balance - 546 - 1000

const simple_send = [
    '6f6d6e69', // omni
    '0000', // version
    toPaddedHexString(31, 8), // 31 for Tether
    ,
    toPaddedHexString(Math.floor(0.1 * 100000000), 16), // amount = 10 * 100 000 000 in HEX
    ,
].join('')

const data = [Buffer.from(simple_send, 'hex')]
const omniOutput = bitcoin.payments.embed({ data }).output
psbt.addOutput({ address: 'mm1oDPm8vjBfdv92yaMacMGfwpdvfFTeoM', value: 546 }) // should be first!
psbt.addOutput({ script: omniOutput, value: 0 }) //0.1 omni
psbt.addOutput({ address: 'ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn', value: reback })

utxo.forEach((item, index, arr) => {
    psbt.signInput(index, alice)
})

psbt.validateSignaturesOfInput(0)

psbt.finalizeAllInputs()

const tx = psbt.extractTransaction().toHex()

console.log(tx)

and I broadcast tx

Here are two IDS I broadcast
2e2888b88291c38248ae5fd1760a37d6c82e9471a52195e5d4d263d6a198a348
c1e55e2d7bb6a57dd80b2e531ee101ba0bfd9b3a137c24cc27a6bb407a403b95

I transferred 0.1 and 0.2 omnin udst to the target address respectively

I don't know how many usdts I have left. I don't know if I have transferred them,

At first, the target address sent me a usdt of Omni, but he said he didn't receive 0.1 and 0.2 from me

I hope someone can help me out. Thank you very much

https://blockexplorer.one/btc/testnet/address/ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn/tokens

This site will show you the omni tokens on testnet for your address.

It seems to show a bunch of weird transactions (property ID 1) and it shows you sending tons of USDT even though you never received any. (1000000000 USDT, but you never received 1000000000 USDT)

https://blockexplorer.one/btc/testnet/address/ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn/tokens

This site will show you the omni tokens on testnet for your address.

It seems to show a bunch of weird transactions (property ID 1) and it shows you sending tons of USDT even though you never received any. (1000000000 USDT, but you never received 1000000000 USDT)

Thank you very much for your reply. I'm glad to find out the tokens. I haven't got a clue before
thx, I got my omni tokens, I sent three deals in all
once amount = 10 * 100 000 000 in HEX so 1000000000 USD maybe

Later, I knew that someone had transferred a usdt to me, so I changed the quantity to 0.1 and 0.2 and sent them twice, that is to say, neither of them succeeded, but in fact, none of them succeeded. The first time was because I didn't have so many usdts,

const simple_send = [
    '6f6d6e69', // omni
    '0000', // version
    toPaddedHexString(31, 8), // 31 for Tether
    ,
    toPaddedHexString(Math.floor(0.1 * 100000000), 16), // amount = 10 * 100 000 000 in HEX
    ,
].join('')

toPaddedHexString(Math.floor(0.1 * 100000000), 16), What's wrong with that

You have 0 USDT on the address ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn.

hello
I have a transfer of 1000000000 usdt ,you can see
https://blockexplorer.one/omni/testnet/tx/ea25df450df470b27f4c9e98b24bd28d7e6e449b46446880ea7ebfd8413b0ae3
my code like this:
const simple_send = [
"6f6d6e69", // omni
"0000", // version
"00000000001f", // 31 for Tether
"000000003B9ACA00" // amount = 10 * 100 000 000 in HEX
].join('')
so it works

and you say I have 0 USDT on the address ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn.

My understanding is USDT Property ID is 31 ,Is that so?

through

https://blockexplorer.one/btc/testnet/address/ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn/tokens

image

I have 1.2 ( Property ID : 1 ),I don't know what it's called
Now I'm trying to transfer out the 1.2 coin. I've tried property 1 and property 31, but none of them works

What I want to ask now is, if I need to transfer this 1.2 coin, How should be filled in, simple_send

"00000000001f", // 31 for Tether

Here you should select 1 instead of 31 (1f is HEX for 31)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

coingeek picture coingeek  Â·  4Comments

zhaozhiming picture zhaozhiming  Â·  3Comments

Mr-Mondragon picture Mr-Mondragon  Â·  3Comments

panpan2 picture panpan2  Â·  3Comments

dakk picture dakk  Â·  3Comments