Skip to content

Instantly share code, notes, and snippets.

@robertDurst
Last active May 29, 2018 21:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robertDurst/78df79857e3b57e89f8dec5731fea400 to your computer and use it in GitHub Desktop.
Save robertDurst/78df79857e3b57e89f8dec5731fea400 to your computer and use it in GitHub Desktop.
Proposed SEP007 approaches for dealing with empty/null public key.

SEP007 Stellar-JS-SDK Integration

Background

As part of the protocol outlined in SEP007, to create a uri without a known source account beforehand, you must specify the source account in the XDR as all zeros.

xdr (required) - A Stellar transaction in XDR format that is base64 encoded and then URL-encoded. If the source account in the xdr is all zeros then the URI handler should replace the source account and sequence number with the user's source account and sequence number before it signs it. If the source account is set and the sequence number is 0 then the URI handler should replace only the sequence number before signing.

Currently this is not possible in the Stellar-JS-SDK.

Overview

Here I present three possible approaches for integrating SEP007 into the Stellar-JS-SDK. Each approach is briefly described and then presented below.

Regarding the first approach, Nikhil said the reference implementation is not correct... so disregard that.

From the second and third approaches, I think that the second approach may be the best. The reason here is that the changes I had to make for the third to work are a little iffy -- I had to accept an empty public key which may be added accidentally versus "00000000000000000000000000000000" is a more intentional addition.

Here is the code change (works for both second and third approaches):

    if (publicKey === "00000000000000000000000000000000" || !publicKey) {
      return new this({type: 'ed25519', publicKey: "00000000000000000000000000000000"});
    }

This code would be inserted here.

/*
In the first approach, no changes need to be made to the existing stellar js sdk.
In this approach I mimick the Go reference implementation and use the master
keypair of the empty string network passphrase.
*/
// 1. build the partial transaction (excludes the source account and sequence numbers
// Define an empty address
s.Network.use(new s.Network(""));
const emptyAddress_a1 = s.Keypair.master().publicKey();
// Define an account
const account_a1 = new s.Account(emptyAddress_a1, "0");
// Define a transaction object
let tx_a1 = new s.TransactionBuilder(account_a1);
// Add payment operation
tx_a1.addOperation(s.Operation.payment({
destination: "GASIA4ZTLZEF4TRLLDQCQIT43KNZKSAEU3PX3BQVNEZVNJ4FM7LBIPTK",
asset: s.Asset.native(),
amount: "1",
}))
// Add a memo if included (Optional)
tx_a1.addMemo(s.Memo.text("SEP, SEP 007"));
// 2. Convert to a transaction envelope
tx_a1 = tx_a1.build().toEnvelope();
// 3. Convert to Base64
tx_a1 = tx_a1.toXDR('base64');
// 4. Url encode (Optional)
const url_a1 = encodeURIComponent(tx_a1);
// 5. Print out ("web+stellar:tx?xdr=" + urlEncoded) (Optional)
console.log(`web+stellar:tx?xdr=${url_a1}`);
/*
Result:
web+stellar:tx?xdr=AAAAAL6Qe0ushP7lzogR2y3vyb8LKiorvD1U2KIlfs1wRBliAAAAZAAAAAAAAAABAAAAAAAAAAEAAAAMU0VQLCBTRVAgMDA3AAAAAQAAAAAAAAABAAAAACSAczNeSF5OK1jgKCJ82puVSASm332GFWkzVqeFZ9YUAAAAAAAAAAAAmJaAAAAAAAAAAAA%3D
*/
/*
This second approach is identical to the first, however the empty address
keypair generation is different. Here I define an empty public key as the
public key created from the string of 32 zeros.
In order to make this work, I had to make one change to the js stellar sdk
codebase. In the keypair.js file, I added a case to the fromPublicKey method
that accepts "00000000000000000000000000000000" and returns a keypair generated
from this string. This adds three lines of code.
*/
// 1. build the partial transaction (excludes the source account and sequence numbers
// Define an empty address
const emptyAddress_a2 = s.Keypair.fromPublicKey("00000000000000000000000000000000").publicKey();
// Define an account
const account_a2 = new s.Account(emptyAddress_a2, "0");
// Define a transaction object
let tx_a2 = new s.TransactionBuilder(account_a2);
// Add payment operation
tx_a2.addOperation(s.Operation.payment({
destination: "GASIA4ZTLZEF4TRLLDQCQIT43KNZKSAEU3PX3BQVNEZVNJ4FM7LBIPTK",
asset: s.Asset.native(),
amount: "1",
}))
// Add a memo if included (Optional)
// tx_a2.addMemo(s.Memo.text("SEP, SEP 007"));
// 2. Convert to a transaction envelope
tx_a2 = tx_a2.build().toEnvelope();
// 3. Convert to Base64
tx_a2 = tx_a2.toXDR('base64');
// 4. Url encode (Optional)
const url_a2 = encodeURIComponent(tx_a2);
// 5. Print out ("web+stellar:tx?xdr=" + urlEncoded) (Optional)
// console.log(`web+stellar:tx?xdr=${url_a2}`);
/*
Result:
web+stellar:tx?xdr=AAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAJIBzM15IXk4rWOAoInzam5VIBKbffYYVaTNWp4Vn1hQAAAAAAAAAAACYloAAAAAAAAAAAA%3D%3D
*/
/*
This third approach is nearly identical to the second. The only difference is
here I define an empty public key as the public key created from the empty
string.
In order to make this work, I had to make one change to the js stellar sdk
codebase. In the keypair.js file, I added a case to the fromPublicKey method
that accepts "" and returns a keypair generated from the
"00000000000000000000000000000000" string. This adds three lines of code.
*/
// 1. build the partial transaction (excludes the source account and sequence numbers
// Define an empty address
const emptyAddress_a3 = s.Keypair.fromPublicKey("").publicKey();
// Define an account
const account_a3 = new s.Account(emptyAddress_a3, "0");
// Define a transaction object
let tx_a3 = new s.TransactionBuilder(account_a3);
// Add payment operation
tx_a3.addOperation(s.Operation.payment({
destination: "GASIA4ZTLZEF4TRLLDQCQIT43KNZKSAEU3PX3BQVNEZVNJ4FM7LBIPTK",
asset: s.Asset.native(),
amount: "1",
}))
// Add a memo if included (Optional)
// tx_a2.addMemo(s.Memo.text("SEP, SEP 007"));
// 2. Convert to a transaction envelope
tx_a3 = tx_a3.build().toEnvelope();
// 3. Convert to Base64
tx_a3 = tx_a3.toXDR('base64');
// 4. Url encode (Optional)
const url_a3 = encodeURIComponent(tx_a3);
// 5. Print out ("web+stellar:tx?xdr=" + urlEncoded) (Optional)
// console.log(`web+stellar:tx?xdr=${url_a3}`);
/*
Result:
web+stellar:tx?xdr=AAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAJIBzM15IXk4rWOAoInzam5VIBKbffYYVaTNWp4Vn1hQAAAAAAAAAAACYloAAAAAAAAAAAA%3D%3D
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment