-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add temporary salt impl * program interface + pda * switch to lib + cleanup * more cleanup * refactor * remove print
- Loading branch information
1 parent
c083872
commit 0934d1d
Showing
9 changed files
with
170 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
solana/src/commonMain/kotlin/com/solana/programs/Program.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.solana.programs | ||
|
||
import com.funkatronics.hash.Sha256 | ||
import com.funkatronics.salt.isOnCurve | ||
import com.solana.publickey.ProgramDerivedAddress | ||
import com.solana.publickey.PublicKey | ||
import com.solana.publickey.SolanaPublicKey | ||
import kotlin.jvm.JvmStatic | ||
|
||
interface Program { | ||
val programId: SolanaPublicKey | ||
|
||
suspend fun createDerivedAddress(seeds: List<ByteArray>) = | ||
createDerivedAddress(seeds, programId) | ||
|
||
suspend fun findDerivedAddress(seeds: List<ByteArray>) = | ||
findDerivedAddress(seeds, programId) | ||
|
||
companion object { | ||
@JvmStatic | ||
suspend fun findDerivedAddress(seeds: List<ByteArray>, programId: PublicKey) = | ||
ProgramDerivedAddress.find(seeds, programId) | ||
|
||
@JvmStatic | ||
suspend fun createDerivedAddress(seeds: List<ByteArray>, programId: PublicKey): Result<SolanaPublicKey> { | ||
val address = Sha256.hash( | ||
seeds.foldIndexed(ByteArray(0)) { i, a, s -> | ||
require(s.size <= 32) { "Seed length must be <= 32 bytes" }; a + s | ||
} + programId.bytes + "ProgramDerivedAddress".encodeToByteArray() | ||
) | ||
|
||
if (address.isOnCurve()) { | ||
return Result.failure( | ||
IllegalArgumentException("Invalid seeds, address must fall off curve") | ||
) | ||
} | ||
|
||
return Result.success(SolanaPublicKey(address)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
solana/src/commonMain/kotlin/com/solana/publickey/Extensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.solana.publickey | ||
|
||
import com.funkatronics.salt.isOnCurve | ||
|
||
suspend fun PublicKey.isOnCurve() = bytes.isOnCurve() |
31 changes: 31 additions & 0 deletions
31
solana/src/commonMain/kotlin/com/solana/publickey/ProgramDerivedAddress.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.solana.publickey | ||
|
||
import com.funkatronics.salt.isOnCurve | ||
import com.solana.programs.Program | ||
import kotlin.jvm.JvmStatic | ||
|
||
class ProgramDerivedAddress private constructor(bytes: ByteArray, val nonce: UByte) : SolanaPublicKey(bytes) { | ||
|
||
private constructor(publicKey: PublicKey, nonce: UByte) : this(publicKey.bytes, nonce) | ||
|
||
companion object { | ||
@JvmStatic | ||
suspend fun find(seeds: List<ByteArray>, programId: PublicKey): Result<ProgramDerivedAddress> { | ||
for (bump in 255 downTo 0) { | ||
val result = Program.createDerivedAddress(seeds + byteArrayOf(bump.toByte()), programId) | ||
if (result.isSuccess) return result.map { ProgramDerivedAddress(it, bump.toUByte()) } | ||
} | ||
return Result.failure(Error("Unable to find valid derived address for provided seeds")) | ||
} | ||
|
||
@JvmStatic | ||
suspend fun create(bytes: ByteArray, nonce: UByte): ProgramDerivedAddress { | ||
require(!bytes.isOnCurve()) { "Provided public key is not a PDA, address must be off Ed25519 curve" } | ||
return ProgramDerivedAddress(bytes, nonce) | ||
} | ||
|
||
@JvmStatic | ||
suspend fun create(publicKey: PublicKey, nonce: UByte) = | ||
ProgramDerivedAddress(publicKey.bytes, nonce) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
solana/src/commonTest/kotlin/com/solana/programs/ProgramTests.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.solana.programs | ||
|
||
import com.solana.publickey.SolanaPublicKey | ||
import kotlinx.coroutines.test.runTest | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertTrue | ||
|
||
class ProgramTests { | ||
|
||
@Test | ||
fun `createProgramAddress returns failure for on chain pubkey`() = runTest { | ||
// given | ||
val seeds = listOf("helloWorld".encodeToByteArray(), byteArrayOf(255.toByte())) | ||
val program = object : Program { | ||
override val programId = SolanaPublicKey.from("11111111111111111111111111111111") | ||
} | ||
|
||
// when | ||
val result = program.createDerivedAddress(seeds) | ||
|
||
// then | ||
assertTrue { result.isFailure } | ||
} | ||
|
||
@Test | ||
fun `createProgramAddress returns expected pubkey for nonce`() = runTest { | ||
// given | ||
val seeds = listOf("helloWorld".encodeToByteArray(), byteArrayOf(252.toByte())) | ||
val expectedPublicKey = SolanaPublicKey.from("THfBMgduMonjaNsCisKa7Qz2cBoG1VCUYHyso7UXYHH") | ||
val program = object : Program { | ||
override val programId = SolanaPublicKey.from("11111111111111111111111111111111") | ||
} | ||
|
||
// when | ||
val result = program.createDerivedAddress(seeds) | ||
|
||
// then | ||
assertTrue { result.isSuccess } | ||
assertEquals(expectedPublicKey, result.getOrNull()!!) | ||
} | ||
|
||
@Test | ||
fun `findProgramAddress returns expected pubkey and nonce`() = runTest { | ||
// given | ||
val seeds = listOf<ByteArray>() | ||
val expectedBump = 255.toUByte() | ||
val expectedPublicKey = SolanaPublicKey.from("Cu7NwqCXSmsR5vgGA3Vw9uYVViPi3kQvkbKByVQ8nPY9") | ||
val program = object : Program { | ||
override val programId = SolanaPublicKey.from("11111111111111111111111111111111") | ||
} | ||
|
||
// when | ||
val result = program.findDerivedAddress(seeds) | ||
|
||
// then | ||
assertTrue { result.isSuccess } | ||
assertEquals(expectedPublicKey, result.getOrNull()!!) | ||
assertEquals(expectedBump, result.getOrNull()!!.nonce) | ||
} | ||
|
||
@Test | ||
fun `findProgramAddress returns expected pubkey and nonce for seeds`() = runTest { | ||
// given | ||
val seeds = listOf("helloWorld".encodeToByteArray()) | ||
val expectedBump = 254.toUByte() | ||
val expectedPublicKey = SolanaPublicKey.from("46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6X") | ||
val program = object : Program { | ||
override val programId = SolanaPublicKey.from("11111111111111111111111111111111") | ||
} | ||
|
||
// when | ||
val result = program.findDerivedAddress(seeds) | ||
|
||
// then | ||
assertTrue { result.isSuccess } | ||
assertEquals(expectedPublicKey, result.getOrNull()!!) | ||
assertEquals(expectedBump, result.getOrNull()!!.nonce) | ||
} | ||
} |