Skip to content

Commit 3c8d081

Browse files
Merge pull request #970 from Concordium/wallet-sdk
Wallet sdk
2 parents d64b810 + 491a9be commit 3c8d081

7 files changed

+1295
-0
lines changed

source/mainnet/net/guides/developer-page.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ All of our repositories are on `GitHub <https://github.com/Concordium>`__.
123123
:maxdepth: 2
124124

125125
sdks-apis
126+
wallet-sdk/wallet-sdk
126127
dapp-examples
127128
../resources/dashboards
128129
../references/developer-tools
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
.. _wallet-sdk-account-transaction:
2+
3+
=========================================
4+
Submit a transaction to a Concordium node
5+
=========================================
6+
7+
The following sections document the requirements for creating an account transaction, signing it, and
8+
sending it to a Concordium node.
9+
10+
* `Construct and sign an account transaction`_
11+
* `Send an account transaction to a Concordium node`_
12+
13+
+++++++++++++++++++++++++++++++++++++++++
14+
Construct and sign an account transaction
15+
+++++++++++++++++++++++++++++++++++++++++
16+
17+
This example constructs and signs a simple transfer, which is an account transaction that moves an amount of CCD from one account to another. For other transaction types, the steps are similar, but the exact fields that must be provided for the payload will be different. Note that Concordium as a whole supports multi-signature transactions, but for the purpose of this example it will demonstrate how to sign for an account with a single credential that has a single key.
18+
19+
Note that when the transaction has been signed anyone with the signature and the transaction will be able to send it to a Concordium node. Therefore it is very important that a wallet requests user approval before utilizing their signing keys.
20+
21+
.. tabs::
22+
23+
.. tab::
24+
25+
TypeScript (Web)
26+
27+
.. code-block:: javascript
28+
29+
import {
30+
AccountAddress,
31+
AccountTransaction,
32+
AccountTransactionHeader,
33+
buildBasicAccountSigner,
34+
CcdAmount,
35+
ConcordiumGRPCWebClient,
36+
ConcordiumHdWallet,
37+
getAccountAddress,
38+
signTransaction,
39+
SimpleTransferPayload,
40+
TransactionExpiry,
41+
} from '@concordium/web-sdk';
42+
43+
const seedPhrase = 'fence tongue sell large master side flock bronze ice accident what humble bring heart swear record valley party jar caution horn cushion endorse position';
44+
const network = 'Testnet'; // Or Mainnet, if working on mainnet.
45+
const wallet = ConcordiumHdWallet.fromSeedPhrase(seedPhrase, network);
46+
47+
const client = new ConcordiumGRPCWebClient(nodeAddress, nodePort);
48+
const cryptographicParameters = await client.getCryptographicParameters();
49+
50+
const credId = wallet.getCredentialId(identityProviderIndex, identityIndex, credNumber, cryptographicParameters);
51+
const sender = getAccountAddress(credId);
52+
53+
const toAddress = AccountAddress.fromBase58('4QkqdUnrjShrUrHpE96odLM6J77nWzEryifzqNnwNk4FYNge8a');
54+
55+
const amount = CcdAmount.fromMicroCcd(5000000);
56+
57+
const payload: SimpleTransferPayload = {
58+
amount,
59+
toAddress
60+
};
61+
62+
const expiry = TransactionExpiry.fromDate(new Date(Date.now() + 360000));
63+
64+
const nonce = (await client.getNextAccountNonce(sender)).nonce;
65+
66+
const header: AccountTransactionHeader = {
67+
expiry:
68+
nonce,
69+
sender,
70+
};
71+
72+
const transaction: AccountTransaction = {
73+
type: AccountTransactionType.Transfer,
74+
payload,
75+
header,
76+
};
77+
78+
const signingKey = wallet.getAccountSigningKey(identityProviderIndex, identityIndex, credNumber);
79+
const signer = buildBasicAccountSigner(signingKey.toString('hex'));
80+
81+
const signature = await signTransaction(accountTransaction, signer);
82+
83+
.. tab::
84+
85+
Kotlin (Android)
86+
87+
.. code-block:: Kotlin
88+
89+
import cash.z.ecc.android.bip39.Mnemonics
90+
import cash.z.ecc.android.bip39.toSeed
91+
import com.concordium.sdk.ClientV2
92+
import com.concordium.sdk.Connection
93+
import com.concordium.sdk.TLSConfig
94+
import com.concordium.sdk.crypto.wallet.ConcordiumHdWallet
95+
import com.concordium.sdk.crypto.wallet.Network
96+
import com.concordium.sdk.requests.BlockQuery
97+
import com.concordium.sdk.transactions.CCDAmount
98+
import com.concordium.sdk.transactions.CredentialRegistrationId
99+
import com.concordium.sdk.transactions.Expiry
100+
import com.concordium.sdk.transactions.Index
101+
import com.concordium.sdk.transactions.SignerEntry
102+
import com.concordium.sdk.transactions.TransactionFactory
103+
import com.concordium.sdk.transactions.TransactionSigner
104+
import com.concordium.sdk.types.AccountAddress
105+
106+
fun createTransferTransaction(): TransferTransaction {
107+
val seedPhrase = "fence tongue sell large master side flock bronze ice accident what humble bring heart swear record valley party jar caution horn cushion endorse position"
108+
109+
@OptIn(ExperimentalStdlibApi::class)
110+
val seedAsHex = Mnemonics.MnemonicCode(seedPhrase!!.toCharArray()).toSeed().toHexString()
111+
val network = Network.TESTNET // Or Network.MAINNET, if working on mainnet.
112+
val wallet = ConcordiumHdWallet.fromHex(seedAsHex, Network.TESTNET)
113+
114+
val connection = Connection.newBuilder()
115+
.host(nodeAddress)
116+
.port(nodePort)
117+
.useTLS(TLSConfig.auto())
118+
.build()
119+
val client = ClientV2.from(connection)
120+
121+
val cryptographicParameters = client.getCryptographicParameters(BlockQuery.BEST)
122+
123+
val credId = wallet.getCredentialId(identityProviderIndex, identityIndex, credNumber, cryptographicParameters.onChainCommitmentKey.toHex())
124+
val sender = AccountAddress.from(CredentialRegistrationId.from(credId))
125+
126+
val toAddress = AccountAddress.from("4QkqdUnrjShrUrHpE96odLM6J77nWzEryifzqNnwNk4FYNge8a")
127+
val amount = CCDAmount.from(5000000)
128+
129+
val nonce = client.getNextAccountSequenceNumber(sender)
130+
val expiry = Expiry.createNew().addMinutes(5)
131+
132+
val signingKey = wallet.getAccountSigningKey(identityProviderIndex, identityIndex, credNumber)
133+
134+
val signer = TransactionSigner.from(
135+
SignerEntry.from(
136+
Index.from(0), Index.from(0),
137+
signingKey
138+
)
139+
)
140+
return TransactionFactory.newTransfer().sender(sender).receiver(toAddress).amount(amount)
141+
.nonce(nonce).expiry(expiry).signer(signer).build()
142+
}
143+
144+
.. tab::
145+
146+
Swift (iOS)
147+
148+
The Swift SDK for iOS is still in development.
149+
150+
++++++++++++++++++++++++++++++++++++++++++++++++
151+
Send an account transaction to a Concordium node
152+
++++++++++++++++++++++++++++++++++++++++++++++++
153+
154+
Finally, when the transaction has been constructed and signed, it is ready to be sent to a Concordium node. The output of the function sending a transaction to a Concordium node is the transaction hash. The transaction hash can then be used to monitor the status of the submitted transaction.
155+
156+
.. tabs::
157+
158+
.. tab::
159+
160+
TypeScript (Web)
161+
162+
.. code-block:: javascript
163+
164+
import {
165+
ConcordiumGRPCWebClient,
166+
} from '@concordium/web-sdk';
167+
168+
const client = new ConcordiumGRPCWebClient(nodeAddress, nodePort);
169+
const transactionHash = await client.sendAccountTransaction(accountTransaction, signature);
170+
171+
.. tab::
172+
173+
Kotlin (Android)
174+
175+
.. code-block:: Kotlin
176+
177+
import com.concordium.sdk.ClientV2
178+
import com.concordium.sdk.Connection
179+
import com.concordium.sdk.TLSConfig
180+
181+
fun main() {
182+
val connection = Connection.newBuilder()
183+
.host(nodeAddress)
184+
.port(nodePort)
185+
.useTLS(TLSConfig.auto())
186+
.build()
187+
val client = ClientV2.from(connection)
188+
val transactionHash = client.sendTransaction(transaction)
189+
}
190+
191+
.. tab::
192+
193+
Swift (iOS)
194+
195+
The Swift SDK for iOS is still in development.

0 commit comments

Comments
 (0)