Completed
Push — master ( 7ac9fb...3b1821 )
by thomas
28:43
created

AddressFactory   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 14

Test Coverage

Coverage 97.67%

Importance

Changes 0
Metric Value
dl 0
loc 131
ccs 42
cts 43
cp 0.9767
rs 10
c 0
b 0
f 0
wmc 19
lcom 0
cbo 14

7 Methods

Rating   Name   Duplication   Size   Complexity  
A fromKey() 0 4 1
A fromScript() 0 4 1
A fromWitnessProgram() 0 4 1
B fromOutputScript() 0 24 6
B fromString() 0 25 6
A isValidAddress() 0 11 2
A getAssociatedAddress() 0 10 2
1
<?php
2
3
namespace BitWasp\Bitcoin\Address;
4
5
use BitWasp\Bitcoin\Base58;
6
use BitWasp\Bitcoin\Bitcoin;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\KeyInterface;
8
use BitWasp\Bitcoin\Key\PublicKeyFactory;
9
use BitWasp\Bitcoin\Network\NetworkInterface;
10
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
11
use BitWasp\Bitcoin\Script\P2shScript;
12
use BitWasp\Bitcoin\Script\ScriptInterface;
13
use BitWasp\Bitcoin\Script\ScriptType;
14
use BitWasp\Bitcoin\Script\WitnessProgram;
15
use BitWasp\Bitcoin\Script\WitnessScript;
16
use BitWasp\Bitcoin\SegwitBech32;
17
use BitWasp\Buffertools\BufferInterface;
18
19
class AddressFactory
20
{
21
    /**
22
     * Returns a pay-to-pubkey-hash address for the given public key
23
     *
24
     * @param KeyInterface $key
25
     * @return PayToPubKeyHashAddress
26
     */
27 44
    public static function fromKey(KeyInterface $key)
28
    {
29 44
        return new PayToPubKeyHashAddress($key->getPubKeyHash());
30
    }
31
32
    /**
33
     * Takes the $p2shScript and generates the scriptHash address.
34
     *
35
     * @param ScriptInterface $p2shScript
36
     * @return ScriptHashAddress
37
     */
38 12
    public static function fromScript(ScriptInterface $p2shScript)
39
    {
40 12
        return new ScriptHashAddress($p2shScript->getScriptHash());
41
    }
42
43
    /**
44
     * @param WitnessProgram $wp
45
     * @return SegwitAddress
46
     */
47 12
    public static function fromWitnessProgram(WitnessProgram $wp)
48
    {
49 12
        return new SegwitAddress($wp);
50
    }
51
52
    /**
53
     * @param ScriptInterface $outputScript
54
     * @return AddressInterface
55
     */
56 44
    public static function fromOutputScript(ScriptInterface $outputScript)
57
    {
58 44
        if ($outputScript instanceof P2shScript || $outputScript instanceof WitnessScript) {
59
            throw new \RuntimeException("P2shScript & WitnessScript's are not accepted by fromOutputScript");
60
        }
61
62 44
        $wp = null;
63 44
        if ($outputScript->isWitness($wp)) {
64
            /** @var WitnessProgram $wp */
65 12
            return new SegwitAddress($wp);
66
        }
67
68 32
        $decode = (new OutputClassifier())->decode($outputScript);
69 32
        switch ($decode->getType()) {
70 32
            case ScriptType::P2PKH:
71
                /** @var BufferInterface $solution */
72 20
                return new PayToPubKeyHashAddress($decode->getSolution());
73 14
            case ScriptType::P2SH:
74
                /** @var BufferInterface $solution */
75 10
                return new ScriptHashAddress($decode->getSolution());
76
            default:
77 4
                throw new \RuntimeException('Script type is not associated with an address');
78
        }
79
    }
80
81
    /**
82
     * @param string $address
83
     * @param NetworkInterface $network
84
     * @return AddressInterface
85
     * @throws \BitWasp\Bitcoin\Exceptions\Base58ChecksumFailure
86
     */
87 60
    public static function fromString($address, NetworkInterface $network = null)
88
    {
89 60
        $network = $network ?: Bitcoin::getNetwork();
90
91
        try {
92 60
            $data = Base58::decodeCheck($address);
93 48
            $prefixByte = $data->slice(0, 1)->getHex();
94
95 48
            if ($prefixByte === $network->getP2shByte()) {
96 12
                return new ScriptHashAddress($data->slice(1));
97 36
            } else if ($prefixByte === $network->getAddressByte()) {
98 36
                return new PayToPubKeyHashAddress($data->slice(1));
99
            }
100 12
        } catch (\Exception $e) {
101
            // continue on for Bech32
102
        }
103
104
        try {
105 14
            return new SegwitAddress(SegwitBech32::decode($address, $network));
106 2
        } catch (\Exception $e) {
107
            // continue on
108
        }
109
110 2
        throw new \InvalidArgumentException("Address not recognized");
111
    }
112
113
    /**
114
     * @param string $address
115
     * @param NetworkInterface $network
116
     * @return bool
117
     * @throws \BitWasp\Bitcoin\Exceptions\Base58ChecksumFailure
118
     */
119 38
    public static function isValidAddress($address, NetworkInterface $network = null)
120
    {
121
        try {
122 38
            self::fromString($address, $network);
123 36
            $is_valid = true;
124 2
        } catch (\Exception $e) {
125 2
            $is_valid = false;
126
        }
127
128 38
        return $is_valid;
129
    }
130
131
    /**
132
     * Following a loose definition of 'associated', returns
133
     * the current script types, and a PayToPubKeyHash address for P2PK.
134
     *
135
     * @param ScriptInterface $script
136
     * @return AddressInterface
137
     * @throws \RuntimeException
138
     */
139 4
    public static function getAssociatedAddress(ScriptInterface $script)
140
    {
141 4
        $classifier = new OutputClassifier();
142 4
        $decode = $classifier->decode($script);
143 4
        if ($decode->getType() === ScriptType::P2PK) {
144 2
            return PublicKeyFactory::fromHex($decode->getSolution())->getAddress();
145
        } else {
146 4
            return self::fromOutputScript($script);
147
        }
148
    }
149
}
150