Transactions

Introduction

Signup provides an easy to use API to process transactions for your users. The idea is to make the micro transactions in browser fast and reliable without storing user's private key in every app they use. In order to make that happen, underneath, Signup is using Spend Tokens which allow the user to trust the application to spend within boundaries.

Spend Tokens

Spend Tokens are cryptographically signed tokens that Signup wallet generates and send it to the web application. The application can use the Spend Token to perform arbitrary transactions on the user's wallet within the defined boundaries allowed by the user. Those boundaries are maximum amount allowed (e.g up to $1), and an expiration which token would be useless afterwards.

How Spend Tokens Are Technically Made?

Spend Tokens are made from a derivation of user's private key that contains three sections of header, payload and signature (all encoded in base64 and concatenated). In order to protect the wallet's entropy from possible vulnerability in the token itself, 32 bytes of the wallet's entropy is slashed before using a HS256 algorithm (HMAC + SHA256). This algorithm generates the hash that will serve as the signature. This way, there is no access to the original wallet's entropy even if a future vulnerability in the token exposes the secret section of the signature.

The payload contains the expiration date and the budget allocated, so is not possible to be replayed in a future date by the application. Signup's non-custodial wallet uses the payload to make sure the transaction request from the application is within the budget or not.

It is also using the internet standard of JWT which is a battle tested internet standard. This token structure is quite common for web developers unfamiliar with crypto as well. Web developers use this token to establish a temporary authorized session with a server. In Signup, JWTs are generated in your browser and are not signed by a centralized server. We believe this technology is used in a non-custodial wallet for the first time!

Requesting Spend Tokens

Before trying to request for any transaction, you need to ask your users to allow permission for that spending to your app. After the execution of this code, a popover appears on the right side of screen, guiding users for connecting to the Signup wallet.

// You can switch this to async/await format
signup.requestSpendToken({
budget: 1.0, // requesting to spend up to $1
})
.then((res) => {
if (res.status === "GRANTED") {
alert("Thanks! you are logged in");
} else {
// user denied permission
}
})
.catch((e) => {
console.log('Something went wrong?', e);
});

This command should be execute only one time in the life time of the session. After that application can perform any transactions up to the limit without repeatitive confirmations.

Performing the Transaction

Performing the transaction after obtaining the token is as easy as this:

// a payment to the developer bch address
signup.pay(5000, "SAT").then(({ txResult }) => {
console.log('Done!, transaction id is =>', txResult.txId);
});

You can alternatively request to spend from other units as well:

signup.pay(0.001, "BCH").then(({ txResult }) => {
console.log('Done!, transaction id is =>', txResult.txId);
});

Or any currencies:

// 5 US Dollar
signup.pay(20, "usd").then(({ txResult }) => {
console.log('Done!, transaction id is =>', txResult.txId);
});
// 20 Malaysian Ringgit
signup.pay(20, "myr").then(({ txResult }) => {
console.log('Done!, transaction id is =>', txResult.txId);
});

Pay to others

You can request your users to pay to other addresses as well (e.g tipping on each other's post). For that you can use the third paramter of pay() function:

signup.pay(5000, "SAT", "bitcoincash:qqn3w48ug4k3j6pd2x6cetgz73ammunsnqhje59ud8")
.then(({ txResult }) => {
console.log('Done!, transaction id is =>', txResult.txId);
});

Error handling for transactions

You can handle the errors happened in processing the transaction using a normal catch JavaScript syntax.

signup.pay(1000, "SAT").then(({ txResult }) => {
console.log('Done!, transaction id is =>', txResult.txId);
}).catch(({status, message}) => {
if (status === 'ERROR') {
console.log(message):
}
});

Or using Try Catch syntax if you're using async await instead of promises:

try {
const { txResult } = await signup.pay(1000, "SAT");
console.log('Done!, transaction id is =>', txResult.txId);
} catch ({status, message}) {
if (status === 'ERROR') {
console.log(message):
}
}