Skip to content

Commit

Permalink
Enable sac interactions (#35)
Browse files Browse the repository at this point in the history
* Implement SAC transfer functionality in walletStore

* Implement SAC transfer functionality in walletStore

* Implement createContractTransferTransaction function

* made modifications

* modifications

* made modifications

* changes made

* fix a couple imports

---------

Co-authored-by: Nathan_akin <[email protected]>
Co-authored-by: llama <[email protected]>
  • Loading branch information
3 people authored Nov 5, 2024
1 parent 1528826 commit 7b2b921
Show file tree
Hide file tree
Showing 5 changed files with 360 additions and 276 deletions.
51 changes: 48 additions & 3 deletions src/lib/stellar/transactions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TransactionBuilder, Networks, Operation, Asset, Memo, Horizon } from '@stellar/stellar-sdk'
import Server from '@stellar/stellar-sdk'
import { TransactionBuilder, Networks, Operation, Asset, Memo, Contract, Horizon, xdr, Address, StrKey, rpc, nativeToScVal } from '@stellar/stellar-sdk'
import { error } from '@sveltejs/kit'

/**
* @module $lib/stellar/transactions
* @description A collection of functions that will generate and return
Expand All @@ -12,6 +12,7 @@ import { error } from '@sveltejs/kit'
* {@link createChangeTrustTransaction}
* {@link createPathPaymentStrictSendTransaction}
* {@link createPathPaymentStrictReceiveTransaction}
* {@link createContractTransferTransaction}
*/

// We are setting a very high maximum fee, which increases our transaction's
Expand All @@ -22,6 +23,7 @@ const maxFeePerOperation = '100000'
const horizonUrl = 'https://horizon-testnet.stellar.org'
const networkPassphrase = Networks.TESTNET
const standardTimebounds = 300 // 5 minutes for the user to review/sign/submit
const rpcUrl = 'https://soroban-testnet.stellar.org'

/**
* For consistency, all functions in this module will return the same type of object.
Expand Down Expand Up @@ -185,7 +187,6 @@ export async function createChangeTrustTransaction({ source, asset, limit }) {
network_passphrase: networkPassphrase,
}
}

/**
* Constructs and returns a Stellar transaction that will contain a path payment strict send operation to send/receive different assets.
* @async
Expand Down Expand Up @@ -331,3 +332,47 @@ export async function createPathPaymentStrictReceiveTransaction({
network_passphrase: networkPassphrase,
}
}

/**
* Constructs and returns a Stellar transaction for transferring assets to a contract or account.
* @async
* @function createContractTransferTransaction
* @param {Object} opts Options object
* @param {string} opts.source Public Stellar address to use as the source account of the transaction
* @param {string} opts.destination Public Stellar address or contract ID to receive the transfer
* @param {string} opts.amount Amount of the asset to transfer
* @param {string} opts.asset Asset to be transferred (example: USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5)
* @returns {Promise<TransactionResponse>} Object containing the relevant network passphrase and the built transaction envelope in XDR base64 encoding, ready to be signed and submitted
*/
export async function createContractTransferTransaction({ source, destination, amount, asset }) {
const server = new rpc.Server(rpcUrl)
const sourceAccount = await server.getAccount(source)

const transaction = new TransactionBuilder(sourceAccount, {
networkPassphrase: networkPassphrase,
fee: maxFeePerOperation,
});

const [assetCode, assetIssuer] = asset.split(':');
const contractId = new Asset(assetCode, assetIssuer).contractId(networkPassphrase);
const contract = new Contract(contractId);

const transferOp = contract.call(
"transfer",
nativeToScVal(source, { type: 'address' }),
nativeToScVal(destination, { type: 'address' }),
nativeToScVal(amount, { type: 'i128' })
)
transaction.addOperation(transferOp);

const builtTransaction = transaction.setTimeout(standardTimebounds).build();

// Simulate the transaction
const rpcServer = new rpc.Server(rpcUrl);
const simulatedTx = await server.prepareTransaction(builtTransaction)

return {
transaction: simulatedTx.toXDR(),
network_passphrase: networkPassphrase,
};
}
13 changes: 11 additions & 2 deletions src/lib/stores/contactsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ function createContactsStore() {
* Adds a new contact entry to the list with the provided details.
* @function add
* @param {ContactEntry} contact Details of new contact entry to add to the list
* @throws Will throw an error if the new contact entry contains an invalid public key in the `address` field
* @throws Will throw an error if the new contact entry contains an invalid public key or contract address in the `address` field
*/
add: (contact) =>
update((list) => {
if (StrKey.isValidEd25519PublicKey(contact.address) || StrKey.isValidContract(contact.address)) {
return [...list, { ...contact, id: uuidv4() }]
} else {
throw error(400, { message: 'invalid public key' })
throw error(400, { message: 'invalid public key or contract address' })
}
}),

Expand Down Expand Up @@ -83,6 +83,15 @@ function createContactsStore() {
return false
}
},

/**
* Checks if the given address is a contract address
* @param {string} address Address to check
* @returns {boolean} True if the address is a contract address, false otherwise
*/
isContractAddress: (address) => {
return StrKey.isValidContract(address)
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/stores/walletStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,4 @@ const setupKeyManager = () => {
keyManager.registerEncrypter(ScryptEncrypter)

return keyManager
}
}
30 changes: 19 additions & 11 deletions src/routes/dashboard/send/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ features have been implemented:
createPathPaymentStrictReceiveTransaction,
createPathPaymentStrictSendTransaction,
createPaymentTransaction,
createContractTransferTransaction,
} from '$lib/stellar/transactions'
// The `open` Svelte context is used to open the confirmation modal
Expand All @@ -62,7 +63,7 @@ features have been implemented:
/** @type {boolean|null} */
let createAccount = null
let pathPayment = false
/** @type {import('stellar-sdk').ServerApi.PaymentPathRecord[]} */
/** @type {import('@stellar/stellar-sdk').Horizon.ServerApi.PaymentPathRecord[]} */
let availablePaths = []
let strictReceive = false
let paymentXDR = ''
Expand Down Expand Up @@ -175,19 +176,27 @@ features have been implemented:
* @function previewPaymentTransaction
*/
const previewPaymentTransaction = async () => {
const destinationAddress = otherDestination ? otherPublicKey : destination;
let { transaction, network_passphrase } = createAccount
? await createCreateAccountTransaction({
source: data.publicKey,
destination: otherDestination ? otherPublicKey : destination,
destination: destinationAddress,
amount: sendAmount,
memo: memo,
})
: contacts.isContractAddress(destinationAddress)
? await createContractTransferTransaction({
source: data.publicKey,
destination: destinationAddress,
asset: sendAsset,
amount: sendAmount,
})
: pathPayment && strictReceive
? await createPathPaymentStrictReceiveTransaction({
source: data.publicKey,
sourceAsset: sendAsset,
sourceAmount: sendAmount,
destination: otherDestination ? otherPublicKey : destination,
destination: destinationAddress,
destinationAsset: receiveAsset,
destinationAmount: receiveAmount,
memo: memo,
Expand All @@ -197,22 +206,22 @@ features have been implemented:
source: data.publicKey,
sourceAsset: sendAsset,
sourceAmount: sendAmount,
destination: otherDestination ? otherPublicKey : destination,
destination: destinationAddress,
destinationAsset: receiveAsset,
destinationAmount: receiveAmount,
memo: memo,
})
: await createPaymentTransaction({
source: data.publicKey,
destination: otherDestination ? otherPublicKey : destination,
destination: destinationAddress,
asset: sendAsset,
amount: sendAmount,
memo: memo,
})
});
// Set the component variables to hold the transaction details
paymentXDR = transaction
paymentNetwork = network_passphrase
paymentXDR = transaction;
paymentNetwork = network_passphrase;
// Open the confirmation modal for the user to confirm or reject the
// transaction. We provide our customized `onConfirm` function, but we
Expand All @@ -221,7 +230,7 @@ features have been implemented:
transactionXDR: paymentXDR,
transactionNetwork: paymentNetwork,
onConfirm: onConfirm,
})
});
}
</script>

Expand Down Expand Up @@ -464,7 +473,6 @@ features have been implemented:

<!-- Button -->
<div class="form-control my-5">
<button class="btn-primary btn" on:click={previewPaymentTransaction}>Preview Transaction</button
>
<button class="btn-primary btn" on:click={previewPaymentTransaction}>Preview Transaction</button>
</div>
<!-- /Button -->
Loading

0 comments on commit 7b2b921

Please sign in to comment.