# Transaction signing

Let `privateKey` is 32 bytes EdDSA private key

Concatenate all bytes of transaction fields (for strings use `utf8` encoding, for numbers such as `nonce` and `timestamp` - 8 bytes big-endian unsigned representation):

```
tags_bytes = concat(sort(tags))
```

```
data = concat(
    space
    key,
    bytes(nonce), // 8 bytes big-endian
    bytes(timestamp), // 8 bytes big-endian
    memo,
    tags_bytes, // concatenated array of tags
    value
)
```

Calculate `hash = sha256(data)`

Sign message `signature = EdDSA.sign(privateKey, hash)`

Create JSON object:

```
signedTransaction = {
    'space': space,
    'key': key,
    'nonce': nonce,
    'timestamp': timestamp,
    'tags': tags,
    'memo': memo,
    'value': value,
    'hash': encodeHex(tx_hash),
    'signature': encodeBase64(signature),
    'public_key': encodeBase64(public_key)
}
```

Create encoded transaction `encodedTransaction=encodeBase64(signedTransaction)`

Call API method `/api/events/add?event={encodedTransaction}`

If transaction is constructed and signed properly this endpoint will return `200 OK` HTTP response. It doesn't mean transaction is immediately add to blockchain as processing is asynchronous. In order to check if transaction succeeded  use provided in documentation API methods.

Here is the reference implementation of transaction signing in NodeJS

```javascript
const axios = require('axios');
const nacl = require('tweetnacl');
const crypto = require('crypto');

const UTF8 = 'utf8';

const EVENT_PATH = '/api/events/add';

const LAST_ID_PATH = '/api/events/last-id';

async function getLastId(nodeUrl, space, key) {
    const params = { space, key };
    const res = await axios.get(nodeUrl + LAST_ID_PATH, { params });
    return res.data;
}

async function sendSignedTransaction(nodeUrl, event) {
    const params = { event };
    const res = await axios.get(nodeUrl + EVENT_PATH, { params });
    return res.data;
}

function signTransaction(privateKey, space, key, nonce, timestamp, value, memo = '', tags = []) {

    const secretKeyBytes = Buffer.from(privateKey, 'base64');

    const keyPair = nacl.sign.keyPair.fromSeed(secretKeyBytes);

    const tagsBuffersList = [];

    tags.forEach(tag => {
        tagsBuffersList.push(Buffer.from(tag, UTF8));
    });

    const tagsBuffer = Buffer.concat(tagsBuffersList);

    const nonceBuffer = Buffer.alloc(8);
    nonceBuffer.writeBigInt64BE(BigInt(nonce));

    const tsBuffer = Buffer.alloc(8);
    tsBuffer.writeBigInt64BE(BigInt(timestamp));

    const messageBuffer = Buffer.concat([
        Buffer.from(space, UTF8),
        Buffer.from(key, UTF8),
        nonceBuffer,
        tsBuffer,
        Buffer.from(memo, UTF8),
        tagsBuffer,
        Buffer.from(value, UTF8)
    ]);

    const hash = crypto.createHash('sha256').update(messageBuffer).digest();

    const signature = nacl.sign.detached(hash, keyPair.secretKey);

    const encodedSignature =  Buffer.from(signature).toString('base64');

    const signedTransaction = {
        'space': space,
        'key': key,
        'nonce': nonce,
        'timestamp': timestamp,
        'tags': tags,
        'memo': memo,
        'value': value,
        'hash': Buffer.from(hash).toString('hex').toUpperCase(),
        'signature': encodedSignature,
        'public_key': Buffer.from(keyPair.publicKey).toString('base64')
    };

    return signedTransaction;

}

function encodeTransaction(signedTransaction) {
    const json = JSON.stringify(signedTransaction);

    return Buffer.from(json).toString('base64')
}

module.exports = {
    signTransaction,
    encodeTransaction,
    getLastId,
    sendSignedTransaction
};
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bloqly.gitbook.io/bloqly/api/transaction-signing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
