Skip to content

Commit

Permalink
Merge pull request #359 from agencyenterprise/feature/kadena-provider
Browse files Browse the repository at this point in the history
Updates | Kadena
  • Loading branch information
kvhnuke authored Oct 19, 2023
2 parents fe8e0b7 + 7ae1a68 commit c2680a4
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 35 deletions.
6 changes: 5 additions & 1 deletion packages/extension/src/providers/kadena/libs/blockies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,15 @@ type options = {
spotcolor?: string;
};

const formatAddress = (address: string): string => {
return address.replace("k:", "0x").toLowerCase();
};

const createIcon = (address: string, opts?: options): string => {
opts = opts || {};
const size = opts.size || 8;
const scale = opts.scale || 4;
const seed = address.toLowerCase();
const seed = formatAddress(address);
seedrand(seed);
const color = opts.color || createColor();
const bgcolor = opts.bgcolor || createColor();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ export class KadenaNetwork extends BaseNetwork {
};

const baseOptions: BaseNetworkOptions = {
basePath: "m/44'/626'/0'",
basePath: "m/44'/626'/0'/0'",
identicon: createIcon,
signer: [SignerType.ed25519kda],
provider: ProviderName.kadena,
api,
importAccount: false,
...options,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const address = computed({
});
const isAddress = computed(() => {
return true;
return !!props.value;
});
const changeFocus = (val: FocusEvent) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ const selectedAsset = ref<KDAToken | Partial<KDAToken>>(
);
const hasEnough = ref(false);
const sendMax = ref(false);
const addressToIsValid = ref(false);
const selected: string = route.params.id as string;
const isLoadingAssets = ref(true);
Expand Down Expand Up @@ -217,6 +218,11 @@ const validateFields = async () => {
)
);
if (rawAmount.lten(0)) {
hasEnough.value = false;
return;
}
const localTransaction = await selectedAsset.value.buildTransaction!(
addressTo.value,
props.accountInfo.selectedAccount,
Expand All @@ -229,30 +235,38 @@ const validateFields = async () => {
localTransaction
);
const partialFee = transactionResult.gas;
const rawFee = toBN(partialFee?.toString() ?? "0");
const gasLimit = transactionResult.metaData?.publicMeta?.gasLimit;
const gasPrice = transactionResult.metaData?.publicMeta?.gasPrice;
const gasFee = gasLimit && gasPrice ? gasLimit * gasPrice : 0;
const rawFee = toBN(
toBase(gasFee.toString(), selectedAsset.value.decimals!)
);
const rawBalance = toBN(selectedAsset.value.balance!);
if (
sendMax.value &&
selectedAsset.value.name === accountAssets.value[0].name
) {
rawAmount = rawAmount.sub(rawFee);
rawAmount = rawBalance.sub(rawFee);
if (rawAmount.gtn(0)) {
amount.value = fromBase(
rawAmount.toString(),
selectedAsset.value.decimals!
);
}
}
if (rawAmount.ltn(0) || rawAmount.add(rawFee).gt(rawBalance)) {
if (rawAmount.add(rawFee).gt(rawBalance)) {
hasEnough.value = false;
} else {
hasEnough.value = true;
}
const nativeAsset = accountAssets.value[0];
const txFeeHuman = fromBase(
partialFee?.toString() ?? "",
rawFee?.toString() ?? "",
nativeAsset.decimals!
);
Expand All @@ -264,6 +278,22 @@ const validateFields = async () => {
nativeSymbol: nativeAsset.symbol ?? "",
nativeValue: txFeeHuman.toString(),
};
const to = props.network.displayAddress(addressTo.value);
if (to.startsWith("k:") && to.length == 66) {
addressToIsValid.value = true;
} else {
const accountDetail = await accountAssets.value[0].getAccountDetails(
to,
props.network
);
if (accountDetail.error) {
addressToIsValid.value = false;
} else {
addressToIsValid.value = true;
}
}
}
};
watch([selectedAsset, addressTo], validateFields);
Expand Down Expand Up @@ -401,6 +431,7 @@ const isDisabled = computed(() => {
amount.value !== "" &&
hasEnough.value &&
addressIsValid &&
addressToIsValid.value &&
!edWarn.value &&
edWarn.value !== undefined
)
Expand Down
3 changes: 3 additions & 0 deletions packages/extension/src/types/base-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface BaseNetworkOptions {
| Promise<BitcoinAPI>
| Promise<KadenaAPI>;
customTokens?: boolean;
importAccount?: boolean;
}

export abstract class BaseNetwork {
Expand Down Expand Up @@ -60,6 +61,7 @@ export abstract class BaseNetwork {
| Promise<BitcoinAPI>
| Promise<KadenaAPI>;
public customTokens: boolean;
public importAccount: boolean;

constructor(options: BaseNetworkOptions) {
this.name = options.name;
Expand All @@ -80,6 +82,7 @@ export abstract class BaseNetwork {
this.decimals = options.decimals;
this.api = options.api;
this.customTokens = options.customTokens ?? false;
this.importAccount = options.importAccount ?? true;
this.coingeckoPlatform = options.coingeckoPlatform;
this.currencyNameLong = options.currencyNameLong;
}
Expand Down
8 changes: 6 additions & 2 deletions packages/extension/src/ui/action/views/accounts/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@
Add hardware wallet account
</a>

<a class="accounts__action-button import" @click="importAction">
<a
v-if="network.importAccount"
class="accounts__action-button import"
@click="importAction"
>
<import-account-icon />
Import account from another wallet
</a>
Expand Down Expand Up @@ -91,7 +95,7 @@
/>

<import-account
v-if="isImportAccount"
v-if="network.importAccount && isImportAccount"
v-bind="$attrs"
:network="network"
@close="closeImportAccount"
Expand Down
4 changes: 2 additions & 2 deletions packages/keyring/tests/generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe("Keyring create tests", () => {
const keyring = new KeyRing(storage);
await keyring.init(password, { mnemonic: MNEMONIC });
const keyAdd: KeyRecordAdd = {
basePath: "m/44'/626'/0'",
basePath: "m/44'/626'/0'/0'/0'",
signerType: SignerType.ed25519kda,
name: "0index",
walletType: WalletType.mnemonic,
Expand All @@ -26,7 +26,7 @@ describe("Keyring create tests", () => {
expect(pair.signerType).equals(SignerType.ed25519kda);
expect(pair.pathIndex).equals(0);
expect(pair.address).equals(
"0x3379098c10716e2ba981a65129e0e7c4b7f11d944412d3ab1001f49114f9d24d"
"0x7359492db65e4e6487134cd68d5620e011965ce50c84f38e613c7bdb47c2bfa3"
);
keyring.lock();
}).timeout(20000);
Expand Down
14 changes: 5 additions & 9 deletions packages/signers/kadena/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { SignerInterface, KeyPair } from "@enkryptcom/types";
import { KeyPair, SignerInterface } from "@enkryptcom/types";
import { bufferToHex, hexToBuffer } from "@enkryptcom/utils";
import { mnemonicToSeedSync } from "bip39";
import { sign as tweetSign } from "tweetnacl";
import { bufferToHex, hexToBuffer } from "@enkryptcom/utils";
import { derivePath } from "./libs/ed25519";

class Signer implements SignerInterface {
async generate(mnemonic: string, derivationPath = ""): Promise<KeyPair> {
const seed = bufferToHex(mnemonicToSeedSync(mnemonic), true);
const dPathSegments = derivationPath.split("/");
const indexVal = Number(dPathSegments.pop());
const keys = derivePath(
dPathSegments.join("/"),
seed,
0x80000000 + indexVal
);
const dPathSegments = `${derivationPath}'`.split("/");

const keys = derivePath(dPathSegments.join("/"), seed);
const keyPair = tweetSign.keyPair.fromSeed(keys.key);
return {
address: bufferToHex(keyPair.publicKey),
Expand Down
18 changes: 9 additions & 9 deletions packages/signers/kadena/tests/generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,34 @@ import Signer from "../src";

describe("Kadena address generate", () => {
const MNEMONIC =
"clip coffee brain token leader kiss around main finger network avoid west";
"favorite service senior cluster chicken shift square endorse casual kidney doll exhibit";

it("should generate Kadena addresses correctly", async () => {
// Arrange
const kadenaSigner = new Signer();

// Act & Assert
let keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0");
let keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/0");
expect(keypair.address).equals(
"0xe84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291"
"0x40a9305bd53a921c44cf19dc9bac4e5d73465fc6a46343ab313defe6b0bfb0a3"
);

// Act & Assert
keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/1");
keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/1");
expect(keypair.address).equals(
"0x2ddd388820dfd8ddafa37a69926e0b5e57d29daa3adab2ede8a390f984038283"
"0x50d824cb62578b1fcf8e4afb122e98884d5f04070950b93a102e1ba1e1f3d1bb"
);

// Act & Assert
keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/2");
keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/2");
expect(keypair.address).equals(
"0x16dcf13ed0261406c63561ef32853e4b417fe1c197a164b6385718c596261918"
"0x287b9cdbd0894fbff67c664b4cc1e7da9eca9b03ef94fd5baa2cfabe2cd3c6a5"
);

// Act & Assert
keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/3");
keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/3");
expect(keypair.address).equals(
"0xaf29ee6f585381b0109eef8ba51f55fbe9cca31c83375efdb8d72588be3995fc"
"0xe00a31c57aabe95554ad71c700c723153c0dd67b072b569916209138e419c122"
);
});
});
10 changes: 5 additions & 5 deletions packages/signers/kadena/tests/sign.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ describe("Kadena signing", () => {
"Everything should be made as simple as possible, but not simpler.";
const msgHash = bufferToHex(blake2AsU8a(msg));
const signature =
"0xed96b2e3e21e021f3b3e0b39b93585705dbbc53a9cf940365f2ea61f71bdd8a68a3272bfc6e79d5f5b89cc32d85a9aba01ce04173038ede70c8d8da8f7cb4506";
"0x8fd01eccc203d17cbffe54393954c213fb087dd6e62cf3c50bc5635346a83d9fae80c214ecb20bab092a0eca10408223e6e1007f597a3d4bfb525d68a0573a05";

const txMsg =
'{"payload":{"exec":{"code":"(coin.transfer-create \\"k:e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291\\" \\"k:e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291\\" (read-keyset \\"ks\\") 0.000000000000)","data":{"ks":{"keys":["e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291"],"pred":"keys-all"}}}},"nonce":"kjs:nonce:1696630965601","signers":[{"pubKey":"e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291","scheme":"ED25519","clist":[{"name":"coin.TRANSFER","args":["k:e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291","k:e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291",{"decimal":"0"}]},{"name":"coin.GAS","args":[]}]}],"meta":{"gasLimit":2500,"gasPrice":1e-8,"sender":"k:e84affbb41a62d74020bc4841ea206aba7734f9e0d30fb688a4a84fe2d30e291","ttl":28800,"creationTime":1696630965,"chainId":"1"},"networkId":"testnet04"}';

const txMsgSig =
"0x8ee1c3cd94602b96a8ee59488c7ee7b0ff464b169513bd42872423219fa291c093bd791f62a11dd7aa00dfd3fa8e4b613e364ea9e4de4afe3d84ce3556673102";
"0xe929eecf16d77016646a95448fd24de3183488a5e4ab7ae0b1fcb5971fd6e3a524a6cc2879b2369e40f827b816355dbaad09b173442742c39ba487c68199a302";
it("it should sign correctly", async () => {
// Arrange
const kadenaSigner = new Signer();
const keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/1");
const keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/1");

// Act
const signResult = await kadenaSigner.sign(msgHash, keypair);
Expand All @@ -33,7 +33,7 @@ describe("Kadena signing", () => {
it("it should sign tx msgs correctly", async () => {
// Arrange
const kadenaSigner = new Signer();
const keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0");
const keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/0");
const txMsgHash = bufferToHex(blake2AsU8a(txMsg));
// Act
const signResult = await kadenaSigner.sign(txMsgHash, keypair);
Expand All @@ -44,7 +44,7 @@ describe("Kadena signing", () => {
it("it should verify correctly", async () => {
// Arrange
const kadenaSigner = new Signer();
const keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/1");
const keypair = await kadenaSigner.generate(MNEMONIC, "m/44'/626'/0'/0'/1");

// Act
const verifyResult = await kadenaSigner.verify(
Expand Down

1 comment on commit c2680a4

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.