Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions Tokens/stockpaydividend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,130 @@ Provides basic understanding from the ground up.
[Sample - TokenSDK with Account](https://github.com/corda/accounts/tree/master/examples/tokens-integration-test)
An basic sample of how account feature can be integrated with TokenSDK

## Bridging To Solana

### Running on Solana Dev Net

Build nodes:

```bash
./gradlew deployNodes
```

Create Solana Accounts and Fund accounts of WayneCo and the BridgingAuthority, create Mint and TokenAccount to be
bridged to:

```bash
./gradlew setupSolanaAccounts
```

Amend `BrigindAuthority` Cordapp's configuration with mappings to newly created accounts:

```bash
./gradlew expandBACordappConfig
```

Run nodes:

```bash
./build/nodes/runnodes
```

### Running with Solana Local Validator

Start a local solana validator with the notary program deployed following instruction from Corda Enterprise.
(the below commands can be run in one go from `./addCordaNetwork.sh` script).

Add the new network and Notary key to Solana. This Notary will be used by the Corda nodes.
```bash
ADMIN_CLI="solana-aggregator/admin-cli/build/libs/admin-cli-4.14-SNAPSHOT.jar"
java -jar $ADMIN_CLI create-network -u http://localhost:8899 -v -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
```

The command will output confirmation with network ID `1`:

```
Creating network ...
✓ Corda network creation successful - network ID: 1
```

Add the Notary key to the network:

```bash
> java -jar $ADMIN_CLI authorize --address Dev7chG99tLCAny3PNYmBdyhaKEVcZnSTp3p1mKVb5m5 --network 1 -u http://localhost:8899 -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
```

This command will output:

```
> Authorizing notary Dev7chG99tLCAny3PNYmBdyhaKEVcZnSTp3p1mKVb5m5...
> ✓ Notary authorized successfully: Dev7chG99tLCAny3PNYmBdyhaKEVcZnSTp3p1mKVb5m5
```

You can list the authorized notaries with:

```bash
java -jar $ADMIN_CLI list-notaries -u http://localhost:8899 -v -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
```

The expected output is:
```
Network ID: 0
1. Notary: DevNMdtQW3Q4ybKQvxgwpJj84h5mb7JE218qTpZQnoA3
Network ID: 1
1. Notary: Dev7chG99tLCAny3PNYmBdyhaKEVcZnSTp3p1mKVb5m5
```

Follow the steps from Running on Solana Dev Net.
The only change is to replace Solana Dev Net url with local validator url `http://localhost:8899` in notary config in
`depolyNodes` task.

#### Using the Cordapps

You can check the current balance on Solana Account:

```bash
spl-token balance --address $TOKEN_ACCOUNT
spl-token display $TOKEN_ACCOUNT
```

##### On WayneCo node console:

Issue Stock `TEST` with linearID `6116560b-c78e-4e13-871d-d666a5d032a3` matching configuration in Bridging Authority.

```bash
start CreateAndIssueStock \
symbol: TEST, \
name: "Test Stock", \
currency: USD, \
price: 7.4, \
issueVol: 2000, \
notary: "O=Notary Service,L=Zurich,C=CH", \
linearId: 6116560b-c78e-4e13-871d-d666a5d032a3
```

Move 1000 stock tokens to self to Bridging Authority:

```bash
start MoveStock symbol: TEST, quantity: 1000, recipient: "O=Bridging Authority,L=New York,C=US"
```

##### On BridgingAuthority node console:

This is currently a manual step to showcase how bridging, normally the bridging flow starts automatically as soon as
a participant moves token(s) to the Bridging Authority:

```bash
start GetTokenToBridgeFormatted symbol: TEST
```

```bash
start BridgeTokenRpc tokenRef: { txhash: <TX_HASH>, index: 0 } , bridgeAuthority: "O=Bridging Authority,L=New York,C=US"
```

You can check the current balance on Solana Account has increased:

```bash
spl-token balance --address $TOKEN_ACCOUNT
spl-token display $TOKEN_ACCOUNT
```
6 changes: 6 additions & 0 deletions Tokens/stockpaydividend/addCordaNetwork.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
ADMIN_CLI="solana-aggregator/admin-cli/build/libs/admin-cli-4.14-SNAPSHOT.jar"

java -jar $ADMIN_CLI create-network -u http://localhost:8899 -v -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
java -jar $ADMIN_CLI authorize --address Dev7chG99tLCAny3PNYmBdyhaKEVcZnSTp3p1mKVb5m5 --network 1 -u http://localhost:8899 -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
java -jar $ADMIN_CLI list-notaries -u http://localhost:8899 -v -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import com.r3.corda.lib.tokens.contracts.states.FungibleToken
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.utilities.ProgressTracker

@InitiatingFlow
Expand Down Expand Up @@ -37,3 +38,12 @@ class BridgeToken(
}
}

@StartableByRPC
class BridgeTokenRpc(private val tokenRef: StateRef, private val bridgeAuthority: Party) : FlowLogic<String>() {
@Suspendable
override fun call(): String {
val stateAndRef: StateAndRef<FungibleToken> = serviceHub.toStateAndRef(tokenRef)
val result = subFlow(BridgeToken(stateAndRef, bridgeAuthority))
return result
}
}
95 changes: 93 additions & 2 deletions Tokens/stockpaydividend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ allprojects {
releasesOnly()
}
}

// For SNAPSHOT version
maven {
url "https://software.r3.com/artifactory/r3-corda-dev"
authentication {
basic(BasicAuthentication)
}
credentials {
username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
}
content {
includeGroup 'com.r3.libs'
includeModule 'com.r3.corda', 'corda-shell'
}
}
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
Expand Down Expand Up @@ -137,10 +153,13 @@ dependencies {
cordapp project(":workflows")
cordapp project(":contracts")

cordapp project(":bridging-contracts") // Used in the test
cordapp project(":bridging-flows") // Used in the test

cordaProvided "org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}"
cordaProvided "org.apache.logging.log4j:log4j-web:${log4j_version}"
cordaProvided "org.slf4j:jul-to-slf4j:$slf4j_version"
cordaDriver "net.corda:corda-shell:$corda_release_version"
cordaDriver "com.r3.corda:corda-shell:$corda_release_version"
// Token SDK dependencies.
cordapp "$tokens_release_group:tokens-contracts:$tokens_release_version"
cordapp "$tokens_release_group:tokens-workflows:$tokens_release_version"
Expand All @@ -151,7 +170,18 @@ cordapp {
minimumPlatformVersion corda_platform_version.toInteger()
}

def solanaNotaryKeyFileName = 'Dev7chG99tLCAny3PNYmBdyhaKEVcZnSTp3p1mKVb5m5.json'
def solanaNotaryKeyPath = "$buildDir/extracted/dev-keys/$solanaNotaryKeyFileName"
def custodiedKeysDirectory = "${project.buildDir}/nodes/custodied-keys"
def keysDirectory = "${project.buildDir}/nodes/solana-keys"
def bridgeAuthorityWallet = "${custodiedKeysDirectory}/bridge-authority-wallet.json"
def tokenMintFile = "${keysDirectory}/token-mint.pub"
def bigBankFile = "${keysDirectory}/big-corp.pub"

def linearId = '6116560b-c78e-4e13-871d-d666a5d032a3'

task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
dependsOn('extractDevKey')
nodeDefaults {
projectCordapp {
deploy = false
Expand All @@ -164,7 +194,14 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
}
node {
name "O=Notary,L=London,C=GB"
notary = [validating : false]
notary = [validating : false,
serviceLegalName: "O=Notary Service,L=Zurich,C=CH",
solana : [
notaryKeypairFile: file(solanaNotaryKeyPath).absolutePath,
custodiedKeysDir : file(custodiedKeysDirectory).absolutePath,
rpcUrl: "https://api.devnet.solana.com"
]
]
p2pPort 10002
rpcSettings {
address("localhost:10003")
Expand Down Expand Up @@ -207,6 +244,39 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
}
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
}
node {
name "O=Bridging Authority,L=New York,C=US"
p2pPort 10018
rpcSettings {
address("localhost:10019")
adminAddress("localhost:10047")
}
cordapp(project(':bridging-contracts'))
cordapp(project(':bridging-flows'))
rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]
}
}

tasks.register('expandBACordappConfig') {
doLast {
def pubkey1 = file(bigBankFile).getText('UTF-8').trim()
def pubkey2 = file(tokenMintFile).getText('UTF-8').trim()
def stdout = new ByteArrayOutputStream()
exec { commandLine 'solana-keygen', 'pubkey', "${bridgeAuthorityWallet}"; standardOutput = stdout }
def pubkey3 = stdout.toString('UTF-8').trim()

copy {
from "${project.projectDir}/workflows/src/main/resources"
include 'bridging-flows-template.conf'
into "$buildDir/nodes/BridgingAuthority/cordapps/config"
rename { String name -> name.replace('template', '1.0') }
expand(bigBankAccount: pubkey1,
tokenMintAccount: pubkey2,
bridgeAuthorityAccount: pubkey3,
cordaTokenTypeLinearId: linearId,
bigBankCordaIdentity: "O=WayneCo,L=SF,C=US")
}
}
}

task installQuasar(type: Copy) {
Expand All @@ -216,3 +286,24 @@ task installQuasar(type: Copy) {
}
}

configurations {
libJar {
transitive = false
}
}

dependencies {
libJar 'com.r3.corda.lib.solana:token-bridging-workflows:0.1.0-SNAPSHOT@jar'
}

tasks.register('extractDevKey', Copy) {
from({ zipTree(configurations.libJar.singleFile) }) {
include "dev-keys/$solanaNotaryKeyFileName"
}
into "$buildDir/extracted"
}

tasks.register('setupSolanaAccounts', Exec) {
dependsOn('extractDevKey')
commandLine 'bash', '-x', "$projectDir/setupSolanaAccounts.sh", "$solanaNotaryKeyPath"
}
18 changes: 18 additions & 0 deletions Tokens/stockpaydividend/runSolana.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

#build
./gradlew solana-aggregator:admin-cli:build
cd solana-aggregator/notary-program
anchor build


#start
solana-test-validator --reset --ledger ../admin-cli/build/test-ledger --bpf-program target/deploy/corda_notary-keypair.json target/deploy/corda_notary.so

#new terminal
ADMIN_CLI="solana-aggregator/admin-cli/build/libs/admin-cli-4.14-SNAPSHOT.jar"
solana airdrop -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json --commitment confirmed 10
solana airdrop -k solana-aggregator/notary-program/dev-keys/DevNMdtQW3Q4ybKQvxgwpJj84h5mb7JE218qTpZQnoA3.json --commitment confirmed 10
java -jar $ADMIN_CLI initialize -u http://localhost:8899 -v -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
java -jar $ADMIN_CLI create-network -u http://localhost:8899 -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
java -jar $ADMIN_CLI authorize --address DevNMdtQW3Q4ybKQvxgwpJj84h5mb7JE218qTpZQnoA3 --network 0 -u http://localhost:8899 -k solana-aggregator/notary-program/dev-keys/DevAD5S5AFhTTCmrD8Jg58bDhbZabSzth7Bu6rG4HFYo.json
41 changes: 41 additions & 0 deletions Tokens/stockpaydividend/setupSolanaAccounts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
solana config set --url localhost

NOTARY_ACCOUNT=`solana address -k $1`
solana airdrop 10 $NOTARY_ACCOUNT

bridgeAuthorityWallet=./build/nodes/custodied-keys/bridge-authority-wallet.json
solana-keygen new -o $bridgeAuthorityWallet --no-bip39-passphrase -f

bigBankWallet=./build/nodes/solana-keys/big-corp-wallet.json
solana-keygen new -o $bigBankWallet --no-bip39-passphrase -f

bridgeAuthorityAccount=`solana address -k $bridgeAuthorityWallet`
funderKeyFile=$1
solana transfer $bridgeAuthorityAccount 0.1 --fee-payer $funderKeyFile --from $funderKeyFile --allow-unfunded-recipient

bigBankAccount=`solana address -k $bigBankWallet`
solana transfer $bigBankAccount 0.1 --fee-payer $funderKeyFile --from $funderKeyFile --allow-unfunded-recipient

tokenMintFile=./build/nodes/solana-keys/token-mint.json
solana-keygen new -o $tokenMintFile --no-bip39-passphrase

MINT_ACCOUNT=$(spl-token create-token \
--program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
--mint-authority $bridgeAuthorityAccount \
--fee-payer $bridgeAuthorityWallet \
--decimals 9 \
--output json \
$tokenMintFile | jq -r '.commandOutput.address')

TOKEN_ACCOUNT=$(spl-token create-account \
--program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
--owner $bigBankAccount \
--fee-payer $funderKeyFile \
$MINT_ACCOUNT | awk '/^Creating account / {print $3}')

bigBankPubKeyFile=./build/nodes/solana-keys/big-corp.pub
echo $TOKEN_ACCOUNT >> $bigBankPubKeyFile

tokenMintPubKeyFile=./build/nodes/solana-keys/token-mint.pub
echo $MINT_ACCOUNT >> $tokenMintPubKeyFile
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,20 @@ class GetTokenToBridge(
val tokens: List<StateAndRef<FungibleToken>> = serviceHub.vaultService.tokenAmountsByToken(pointer).states
return tokens
}
}

@InitiatingFlow
@StartableByRPC
class GetTokenToBridgeFormatted(
val symbol: String
) : FlowLogic<List<String>>() {

override val progressTracker = ProgressTracker()

@Suspendable
override fun call(): List<String> {
val tokens: List<StateAndRef<FungibleToken>> = subFlow(GetTokenToBridge(symbol))
val formatted: List<String> = tokens.map { "${it.ref}" }
return formatted
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
participants = {"${bigBankCordaIdentity}" = "${bigBankAccount}"}
mints = {"${cordaTokenTypeLinearId}" = "${tokenMintAccount}"}
mintAuthorities = {"${cordaTokenTypeLinearId}" = "${bridgeAuthorityAccount}"}