Skip to content
Draft
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
16 changes: 16 additions & 0 deletions bitcore-test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@
"threads": 0
}
},
"ARC": {
"testnet": {
"chainSource": "external",
"module": "./moralis",
"trustedPeers": [],
"providers": [
{
"host": "rpc.testnet.arc.network",
"protocol": "https",
"port": "",
"dataType": "combined"
}
],
"threads": 0
}
},
"BASE": {
"sepolia": {
"chainSource": "external",
Expand Down
3 changes: 2 additions & 1 deletion packages/bitcore-client/src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const chainLibs = {
ARB: { Web3, ethers },
BASE: { Web3, ethers },
OP: { Web3, ethers },
ARC: { Web3, ethers },
XRP: xrpl,
SOL: { SolKit, SolanaProgram }
};
Expand Down Expand Up @@ -303,7 +304,7 @@ export class Wallet {
* @returns {Boolean}
*/
isEvmChain() {
return ['ETH', 'MATIC', 'ARB', 'OP', 'BASE'].includes(this.chain?.toUpperCase());
return ['ETH', 'MATIC', 'ARB', 'OP', 'BASE', 'ARC'].includes(this.chain?.toUpperCase());
}

isSolanaChain() {
Expand Down
10 changes: 10 additions & 0 deletions packages/bitcore-client/test/unit/wallet.arc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { expect } from 'chai';
import { Wallet } from '../../src/wallet';

describe('Wallet ARC support', function() {
it('should treat ARC as an EVM chain', function() {
const arcWallet = Object.assign(Object.create(Wallet.prototype), { chain: 'ARC' }) as Wallet;
expect(arcWallet.isEvmChain()).to.equal(true);
expect(arcWallet.getLib()).to.have.keys(['Web3', 'ethers']);
});
});
8 changes: 6 additions & 2 deletions packages/crypto-wallet-core/src/constants/chains.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

export const UTXO_CHAINS = ['btc', 'bch', 'doge', 'ltc'];
export const EVM_CHAINS = ['eth', 'matic', 'arb', 'base', 'op'];
export const EVM_CHAINS = ['eth', 'matic', 'arb', 'base', 'op', 'arc'];
export const SVM_CHAINS = ['sol'];
export const RIPPLE_CHAINS = ['xrp'];
export const CHAINS = [...UTXO_CHAINS, ...EVM_CHAINS, ...SVM_CHAINS, ...RIPPLE_CHAINS];
Expand All @@ -12,7 +12,8 @@ export const EVM_CHAIN_DEFAULT_TESTNET = {
MATIC: 'amoy',
ARB: 'sepolia',
BASE: 'sepolia',
OP: 'sepolia'
OP: 'sepolia',
ARC: 'testnet'
};

export const EVM_CHAIN_NETWORK_TO_CHAIN_ID = {
Expand All @@ -22,6 +23,7 @@ export const EVM_CHAIN_NETWORK_TO_CHAIN_ID = {
ARB_mainnet: 42161,
BASE_mainnet: 8453,
OP_mainnet: 10,
ARC_mainnet: 'unsupported',
// ETH testnets
ETH_holesky: 17000,
ETH_sepolia: 11155111,
Expand All @@ -41,6 +43,8 @@ export const EVM_CHAIN_NETWORK_TO_CHAIN_ID = {
// OP testnets
OP_sepolia: 11155420,
OP_goerli: 28528,
// ARC testnets
ARC_testnet: 5042002,
// Regtests
Comment thread
kajoseph marked this conversation as resolved.
ETH_regtest: 1337,
MATIC_regtest: 13375,
Expand Down
11 changes: 11 additions & 0 deletions packages/crypto-wallet-core/src/constants/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ export const UNITS = {
minDecimals: 2
}
},
arc: {
toSatoshis: 1e18,
full: {
maxDecimals: 6,
minDecimals: 6
},
short: {
maxDecimals: 6,
minDecimals: 2
}
},
xrp: {
toSatoshis: 1e6,
full: {
Expand Down
1 change: 1 addition & 0 deletions packages/crypto-wallet-core/src/derivation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const derivers: { [chain: string]: IDeriver } = {
ARB: new ArbDeriver(),
BASE: new BaseDeriver(),
OP: new OpDeriver(),
ARC: new EthDeriver(),
SOL: new SolDeriver()
};

Expand Down
3 changes: 3 additions & 0 deletions packages/crypto-wallet-core/src/derivation/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export const Paths = {
BASE: {
default: "m/44'/60'/",
},
ARC: {
default: "m/44'/60'/",
},
SOL: {
default: "m/44'/501'/",
},
Expand Down
2 changes: 2 additions & 0 deletions packages/crypto-wallet-core/src/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const providers = {
BASEERC20: new BASEERC20TxProvider(),
OP: new OPTxProvider(),
OPERC20: new OPERC20TxProvider(),
ARC: new ETHTxProvider('ARC'),
ARCERC20: new ERC20TxProvider('ARC'),
SOL: new SOLTxProvider(),
SOLSPL: new SPLTxProvider(),
};
Expand Down
8 changes: 8 additions & 0 deletions packages/crypto-wallet-core/src/validation/arc/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { EthValidation } from '../eth';

export class ArcValidation extends EthValidation {
constructor() {
super();
this.regex = /arc/i;
}
}
2 changes: 2 additions & 0 deletions packages/crypto-wallet-core/src/validation/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ArbValidation } from './arb';
import { ArcValidation } from './arc';
import { BaseValidation } from './base';
import { BchValidation } from './bch';
import { BtcValidation } from './btc';
Expand All @@ -22,6 +23,7 @@ const validation: { [chain: string]: IValidation } = {
ARB: new ArbValidation(),
BASE: new BaseValidation(),
OP: new OpValidation(),
ARC: new ArcValidation(),
SOL: new SolValidation(),
};

Expand Down
12 changes: 12 additions & 0 deletions packages/crypto-wallet-core/test/address.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ describe('Address Derivation', () => {
expect(address).to.equal(expectedAddress);
});

it('should be able to generate a valid ARC address', () => {
const xPub = 'xpub6D8rChqkgFuaZULuq2n6VrS4zB5Cmv24gcRc889dFRRgYAH1CGQmQZ9kcPfMAfWGPnyMd1X5foBYFmJ5ZPfvwhm6tXjaY13ao1rQHRtkKDv';
// 'select scout crash enforce riot rival spring whale hollow radar rule sentence';

const path = Deriver.pathFor('ARC', 'testnet');
expect(path).to.equal("m/44'/60'/0'");

const address = Deriver.deriveAddress('ARC', 'testnet', xPub, 0, false);
const expectedAddress = '0x9dbfE221A6EEa27a0e2f52961B339e95426931F9';
expect(address).to.equal(expectedAddress);
});

it('should be able to generate a valid ETH address, privKey, pubKey', () => {
const privKey = 'xprv9ypBjKErGMqCdzd44hfSdy1Vk6PGtU3si8ogZcow7rA23HTxMi9XfT99EKmiNdLMr9BAZ9S8ZKCYfN1eCmzYSmXYHje1jnYQseV1VJDDfdS';

Expand Down
55 changes: 54 additions & 1 deletion packages/crypto-wallet-core/test/transactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import bitcoreLib from '@bitpay-labs/bitcore-lib';
import bitcoreLibCash from '@bitpay-labs/bitcore-lib-cash';
import bitcoreLibDoge from '@bitpay-labs/bitcore-lib-doge';
import bitcoreLibLtc from '@bitpay-labs/bitcore-lib-ltc';
import { Transactions } from '../src';
import { Constants, Transactions } from '../src';

describe('Transaction', function() {
describe('create', () => {
Expand Down Expand Up @@ -1751,6 +1751,59 @@ describe('Transaction', function() {
});
});

describe('ARC EVM support', () => {
it('should get the correct testnet chainId', () => {
const testnetId = Transactions.get({ chain: 'ARC' }).getChainId('testnet');
expect(testnetId).to.equal(5042002);
});

it('should create an ARC native transaction using 18-decimal base units', () => {
const tx = Transactions.create({
chain: 'ARC',
recipients: [{ address: '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A', amount: '1000000000000000000' }],
nonce: 0,
gasPrice: 1,
gasLimit: 21000,
network: 'testnet',
data: '0x'
});
const parsed = ethers.Transaction.from(tx);
expect(parsed.chainId).to.equal(5042002n);
expect(parsed.value).to.equal(1000000000000000000n);
});

it('should create an ARC ERC20 transaction using ARC testnet chainId', () => {
const tokenAddress = '0x3600000000000000000000000000000000000000';
const recipient = '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
const amount = '1000000';
const tx = Transactions.create({
chain: 'ARCERC20',
recipients: [{ address: recipient, amount }],
nonce: 0,
gasPrice: 1,
gasLimit: 200000,
network: 'testnet',
tokenAddress
});
const parsed = ethers.Transaction.from(tx);

expect(parsed.chainId).to.equal(5042002n);
expect(parsed.to).to.equal(ethers.getAddress(tokenAddress));
expect(parsed.value).to.equal(0n);
expect(parsed.data).to.equal(
'0xa9059cbb' +
'00000000000000000000000037d7b3bbd88efde6a93cf74d2f5b0385d3e3b08a' +
'00000000000000000000000000000000000000000000000000000000000f4240'
);
});

it('should define ARC native units as 18 decimals', () => {
expect(Constants.UNITS.arc.toSatoshis).to.equal(1e18);
expect(Constants.UNITS.arc.full.maxDecimals).to.equal(6);
expect(Constants.UNITS.arc.full.minDecimals).to.equal(6);
});
});

describe('ETH _toHex', function() {
it('should convert number to hex string', function() {
const ETHTxProvider = Transactions.get({ chain: 'ETH' });
Expand Down
21 changes: 21 additions & 0 deletions packages/crypto-wallet-core/test/validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,27 @@ describe('Address Validation', () => {
expect(inValidMaticPrefix).to.equal(false);
});

it('should validate ARC addresses', async () => {
const address = '37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
const prefixedAddress = `0x${address}`;

expect(await Validation.validateAddress('ARC', 'testnet', address)).to.equal(true);
expect(await Validation.validateAddress('ARC', 'testnet', prefixedAddress)).to.equal(true);
expect(await Validation.validateAddress('ARC', 'testnet', address.slice(1))).to.equal(false);
});

it('should validate ARC URIs', async () => {
const address = '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
const uri = `arc:${address}`;
const uriParams = `${uri}?value=123&gasPrice=123&gas=123&gasLimit=123`;

expect(await Validation.validateUri('ARC', uri)).to.equal(true);
expect(await Validation.validateUri('ARC', uriParams)).to.equal(true);
expect(await Validation.validateUri('ARC', `${uri}?value=123`)).to.equal(true);
expect(await Validation.validateUri('ARC', address)).to.equal(false);
expect(await Validation.validateUri('ARC', `${uri}?value=invalid&gasLimit=123&gas=123`)).to.equal(false);
});

it('should be able to validate a SOL address', async () => {
const isValidAddress = await Validation.validateAddress('SOL', 'mainnet', solAddress);
expect(isValidAddress).to.equal(true);
Expand Down