Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an OmniLayer example to tests #1176

Closed
caffeinum opened this issue Aug 15, 2018 · 50 comments
Closed

Add an OmniLayer example to tests #1176

caffeinum opened this issue Aug 15, 2018 · 50 comments

Comments

@caffeinum
Copy link

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

@dcousens
Copy link
Contributor

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

@caffeinum
Copy link
Author

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

@dcousens
Copy link
Contributor

dcousens commented Sep 6, 2018

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

@junderw
Copy link
Member

junderw commented Sep 6, 2018

@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())
  }
})

@junderw
Copy link
Member

junderw commented Sep 6, 2018

@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

@dcousens
Copy link
Contributor

dcousens commented Sep 6, 2018

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?

@junderw
Copy link
Member

junderw commented Sep 7, 2018

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... :-/

@dcousens
Copy link
Contributor

dcousens commented Sep 7, 2018

@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...

@junderw
Copy link
Member

junderw commented Sep 7, 2018

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?

@dcousens
Copy link
Contributor

dcousens commented Sep 7, 2018

@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...

@junderw
Copy link
Member

junderw commented Sep 7, 2018

PSBT to the rescue!

@dcousens
Copy link
Contributor

dcousens commented Sep 7, 2018

@junderw is it though?

@junderw
Copy link
Member

junderw commented Sep 8, 2018

@dcousens hahahahahahahahahaha

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

@Nick-49
Copy link

Nick-49 commented Sep 14, 2018

" 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 .

@junderw
Copy link
Member

junderw commented Sep 14, 2018

Read the Omni Protocol documents.

It should be first because the Omni protocol requires it.

@caffeinum
Copy link
Author

caffeinum commented Sep 14, 2018

@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: #1176 (comment)

@Nick-49
Copy link

Nick-49 commented Sep 15, 2018

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

@ssssssu12
Copy link

ssssssu12 commented Nov 8, 2018

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

It should be change dynamically?

@junderw junderw closed this as completed Nov 8, 2018
@caffeinum
Copy link
Author

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

@yugasun
Copy link

yugasun commented Nov 29, 2018

This is a detailed demo

@junderw
Copy link
Member

junderw commented Nov 30, 2018

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

@yugasun
Copy link

yugasun commented Nov 30, 2018

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

@rohitsahu21
Copy link

@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

@caffeinum
Copy link
Author

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

Did you use NETWORK=mainnet?

@rohitsahu21
Copy link

@caffeinum No i'm using Testnet for Testing purpose

@caffeinum
Copy link
Author

caffeinum commented Jan 11, 2019

@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.

@zinxer
Copy link

zinxer commented Feb 13, 2019

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!

@junderw
Copy link
Member

junderw commented Feb 14, 2019

  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.

@junderw
Copy link
Member

junderw commented Feb 14, 2019

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.

@caffeinum
Copy link
Author

caffeinum commented Feb 14, 2019

@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: MetaMask/metamask-extension#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

@zinxer
Copy link

zinxer commented Feb 14, 2019

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.

@junderw
Copy link
Member

junderw commented Feb 15, 2019

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.

@zinxer
Copy link

zinxer commented Feb 15, 2019

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.

@caffeinum
Copy link
Author

caffeinum commented Feb 15, 2019

@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)

@zinxer
Copy link

zinxer commented Feb 15, 2019

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

@junderw
Copy link
Member

junderw commented Jan 14, 2020

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())
  }
})

@DingGeng-GitHub
Copy link

@junderw

v5.1
It's a test network
According to your latest v5.1 , It is generate a transaction successfully but that Tx Hash not reflect on Omni Blockchain.
hash:0d1cbe2dc0a44f4a28b4e4206490bcc57b7ab9842630fc2cb5b293d11339c853
txRaw:02000000016c198018807bf3cbcac5b3cdb17e01aab2db7e562aacb8dc13d7364b47059532010000006a473044022020cee187538c40479088c03bda62b66d349ada2fea873995490842a312d0909c0220467d520dca411d00ecd05f87c79cf69709b20d4b210c6e6cadeac5c2e3d206ce012103d503dc7b44103147de95b46d6b97b942417090cbaf8d243ad7fee84f067caf1dfeffffff0322020000000000001976a9147d36034630a94241ae48ba14288b73d50608988088ac0000000000000000166a146f6d6e69000000000000001f000000003b9aca00f59d7901000000001976a914ba33eeebd903b3e9ccf874e5e64d989ba37e25e588ac00000000

Does this instance not work on the test network?
Thanks

@junderw
Copy link
Member

junderw commented Jan 15, 2020

You didn't broadcast it to the network.

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

@DingGeng-GitHub
Copy link

@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?

@junderw
Copy link
Member

junderw commented Apr 13, 2020

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

@DingGeng-GitHub
Copy link

@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!

@junderw
Copy link
Member

junderw commented Apr 14, 2020

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.

@junderw
Copy link
Member

junderw commented Apr 14, 2020

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

@DingGeng-GitHub
Copy link

Yes, thank you.

@jeffy7
Copy link

jeffy7 commented Jun 22, 2020

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

@junderw
Copy link
Member

junderw commented Jun 22, 2020

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)

@jeffy7
Copy link

jeffy7 commented Jun 23, 2020

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

@junderw
Copy link
Member

junderw commented Jun 23, 2020

You have 0 USDT on the address ms7f7uEipu9r4B925XoK8mcJ2zLcNbJiJn.

@jeffy7
Copy link

jeffy7 commented Jun 24, 2020

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

@caffeinum
Copy link
Author

"00000000001f", // 31 for Tether

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants